Forum: Projekte & Code Basic-Interpreter auf einem AVR


von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

auf der Webseite:
http://bralug.de/wiki/Basic-Interpreter_f%C3%BCr_AVR_(uBasic-avr)
habe ich angefangen einen Basic-Interpreter für AVRs zu dokumentieren.

Grundlage der Geschichte ist ubasic (http://www.sics.se/~adam/ubasic/), 
welches ich um AVR-spezifische Dinge aufgebohrt habe (bzw. noch dabei 
bin...).

Der entstandene Interpreter ist in C geschrieben, ist relativ 
ressourcenschonend und kann leicht in eigene AVR-Programme integriert 
werden. Es handelt sich also nicht um eine "Standalone-Lösung", wie z.B. 
J.Ws. AVR-ChipBasic-Lösungen.

Grüße Uwe

PS.: Kommentare, Ideen etc. sind ausdrücklich erwünscht...

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Uwe Berger schrieb:
> auf der Webseite:
> http://bralug.de/wiki/Basic-Interpreter_f%C3%BCr_AVR_(uBasic-avr) <<<<
> habe ich angefangen einen Basic-Interpreter für AVRs zu dokumentieren.

ähmm, die abschliessende Klammer bei der URL gehört mit zum Link...

also so: bralug.de/wiki/Basic-Interpreter_für_AVR_(uBasic-avr)

Uwe

von Donald (Gast)


Lesenswert?

Schaue dir mal den BasicBeetle an: www.DieProjektseite.de

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Donald schrieb:
> Schaue dir mal den BasicBeetle an: www.DieProjektseite.de
>
ja, hatte ich schon im Vorfeld gemacht. Was meinst du damit?

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

... vielleicht nochmal zum Verständnis meines Interpreters:

Es geht nicht darum ein Fertiggerät zu haben, was Basic-Programme 
interpretieren kann, wie es z.B. AVR-ChipBasic oder BasicBeetle ist!

Mein Ansatz ist ein anderer: bei mir handelt es sich mehr um eine Art 
Library, die in eigene Mikrocontroller-Programme mit eingebunden werden 
kann, um z.B. auf bestehender Firmware Programmfragmente nachladen und 
ausführen zu können. Im derzeit vorliegenden Quelltext ist mindestens 
ungeklärt, wie der Basic-Quelltext in den Mikrocontroller kommt. Es 
werden nur die entsprechenden Schnittstellen zur Verfügung gestellt. Das 
Testprogramm zeigt nur eine Möglichkeit über die serielle Schnittstelle 
auf.

Klar könnte man aus dieser Library auch solche Komplettgeräte, wie ganz 
oben erwähnt programmieren, aber wie gesagt, dass will ich ja gar 
nicht...

Grüße Uwe

von Rene B. (themason) Benutzerseite


Lesenswert?

@uwe

Schöne Adaption des uBasics. Hatte mir den Code mal vor 2-3 Jahren 
angeschaut, und war schon recht beeindruckt von der Größe. Und es ist 
eine gute Grundlage zum Verständnis eines Interpreters. Für mein 
geplantes Basic hat mir der Code vom Dunklen Adam ;-P auf jedenfall 
geholfen. Bei meinem Basic (ich werds bei dem geplanten Funktionsumfang 
wohl nicht uBasic oder TinyBasic oder so nennen können :))) wird es 
keine Zeilennummern geben, es soll Prozeduren/Funktionen geben und wenn 
ich es hinbekomme wirds auch die Möglichkeit geben Programmteile 
"nachzuladen" (sprich zur Laufzeit ausführen).
Mal schauen wie weit ich komme.

von tüddel (Gast)


Lesenswert?

Cool wäre es, ein "Program" von einer externen Quelle (I²C EEPROM, 
SDCARD oder UART) Nachzuladen.
Ich habe soetwas schon lange vor, aber mit einer AWL-Angehauchten 
Syntax, damit auch "Elektricker" damit was anfangen können ;-)

von Rene B. (themason) Benutzerseite


Lesenswert?

@tüddel

Im Prinzip wäre der Parser den ich hier in der Code-Sammlung vorgestellt 
habe geeignet für soetwas.
Einfach die Befehle für die AWL-Sprache definieren, die Funktionen dazu 
implementieren (also den C Code für die einzelnen AWL Befehle), 
SD-Karten/EEP-Unterstützung hinzufügen (das man Zeile für Zeile auslesen 
kann, und die aktuelle Lese-Position setzen/holen kann für 
Sprung-Befehle), und schon hat man ein brauchbares Grundgerüst.
Nur mal so als Vorschlag.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

tüddel schrieb:
> Cool wäre es, ein "Program" von einer externen Quelle (I²C EEPROM,
> SDCARD oder UART) Nachzuladen.
>
ist im Prinzip möglich, in meiner Doku (obiger Link) habe ich ja 
geschrieben, dass der Quelltext der Funktion ubasic_init() übergeben 
werden muss. Um das Parameter zu füllen, dann man seinen eigenen Weg 
gehen. Desweiteren könnte man auch gleich mit einem anderen Medium 
arbeiten (z.B. SD-Card), muss dann aber den Quelltext an den 
entsprechenden Stellen abändern.

Mein Plan ist es auch, das basic-Programm von SD-Card zu lesen...

Das die ganze Geschichte ein Basic darstellt, ist Zufall, weil ich halt 
uBasic gefunden hatte. Aber man könnte auch einen anderen Sprach-Dialekt 
auf der Grundlage aufsetzen. Ich finde uBasic zeigt sehr schön, wie man 
vorgehen könnte....

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

neben einiger Bug-Fixes und kleinerer Erweiterungen des Sprachumfanges, 
ist in der neuen Version die Implementierung des call-Befehles 
hervorzuheben.

Mit diesem Mechanismus (siehe Quellcode und dort enthaltene 
Kurz-Referenzen) ist es möglich relativ einfach vorhandene C-Funktionen 
in den Basic-Interpreter einzubinden, um sie im Basic-Programm nach dem 
Muster:
1
...
2
10 call("function1", 1, 20)
3
...

oder auch
1
...
2
10 a=call("function2", 120)
3
...

aufzurufen.

Der Quellcode ist auf oben benannter Webseite zu finden.

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

die neueste, auf obiger Webseite abgelegte, Version ermöglicht einen 
Durchgriff auf interne C-Variablen via Basic-Befehl.

Desweiteren habe ich mir mal die Mühe gemacht eine Doku zu schreiben, 
die ebenfalls im Quelltextarchiv zu finden ist.

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

ich habe mal die URL der entsprechenden Projektseite so geändert, dass 
sie besser lesbar und angebbar ist. Sie lautet jetzt:

http://bralug.de/wiki/UBasic-avr

(Der alte Link funktioniert ebenfalls.)

Desweiteren sind die Basic-Befehle vpeek und vpoke hinzu gekommen, mit 
denen man sich einen Zugriff auf interne C-Variablen verschaffen kann.

Im Quelltext-Archiv ist nunmehr eine kleine Dokumentation zu finden, 
welche zum einen als Kurzreferenz für die Basic-Befehle zu verstehen 
ist. Zum anderen wird dort versucht zu erläutern, wie man uBasic in 
eigene Programme einbinden kann.

Grüße Uwe

von roman65536 (Gast)


Lesenswert?

Uwe,

ich habe den interpreter noch ein bisschen erweitert.. falls es dich 
interessiert.. um xor und die shift ops.. nuetzlich wenn man mit bit's 
arbeitet ..

Dann kann man so was tun :
 print 1+1, 15 ^ 1 , 1 shl 2
was ergibt :
2 14 4


lg roman


hier meine aenderungen :

tokenizer.h :

..
 TOKENIZER_AND,
  TOKENIZER_OR,
  TOKENIZER_XOR,
  TOKENIZER_LSH,
  TOKENIZER_RSH,
  TOKENIZER_ASTR,
  TOKENIZER_SLASH,
  TOKENIZER_MOD,
...

tokenizer.c
...
  {"shl", TOKENIZER_LSH},
  {"shr", TOKENIZER_RSH},
  {NULL, TOKENIZER_ERROR}
...
  } else if(*ptr == '%') {
    return TOKENIZER_MOD;
  } else if(*ptr == '^') {
    return TOKENIZER_XOR;

  } else if(*ptr == '(') {
    return TOKENIZER_LEFTPAREN;
  } else if(*ptr == ')') {
..

dann noch ubasic.c:

/*---------------------------------------------------------------------- 
-----*/
static int
expr(void)
{
  int t1, t2;
  int op;

  t1 = term();
  op = tokenizer_token();
  DEBUG_PRINTF("expr0: token %d\n", op);
  while(op == TOKENIZER_PLUS ||
        op == TOKENIZER_MINUS ||
        op == TOKENIZER_AND ||
        op == TOKENIZER_OR  ||
        op == TOKENIZER_XOR ||
        op == TOKENIZER_LSH ||
        op == TOKENIZER_RSH )
 {
    tokenizer_next();
    t2 = term();
    DEBUG_PRINTF("expr1: %d %d %d\n", t1, op, t2);
    switch(op) {
    case TOKENIZER_PLUS:
      t1 = t1 + t2;
      break;
    case TOKENIZER_MINUS:
      t1 = t1 - t2;
      break;
    case TOKENIZER_AND:
      t1 = t1 & t2;
      break;
    case TOKENIZER_OR:
      t1 = t1 | t2;
      break;
    case TOKENIZER_XOR:
      t1 = t1 ^ t2;
      break;
    case TOKENIZER_LSH:
      t1 = t1 << t2;
      break;
    case TOKENIZER_RSH:
      t1 = t1 >> t2;
      break;
    }
    op = tokenizer_token();
  }

..

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

roman65536 schrieb:
> ich habe den interpreter noch ein bisschen erweitert.. falls es dich
> interessiert.. um xor und die shift ops.. nuetzlich wenn man mit bit's
> arbeitet ..
>
stimmt, die Funktionen hören sich interessant an, ich werde sie in 
meiner Version aufnehmen...

Nebenbei, ich bin gerade dabei den Code etwas speicherplatzmäßig zu 
optimieren. Es geht dabei vorallem darum den SRAM des AVR 
freizuschaufeln und konstante Felder (z.B. die Tabelle keywords des 
Tokenizers) optional in den Flash verlagern zu können. Das wird 
ebenfalls in der nächsten öffentlichen Version enthalten sein.

Grüße & Danke Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

auf der Projektseite http://bralug.de/wiki/UBasic-avr ist eine neue 
Version verfügbar. Folgende Erweiterungen:

* eine interne statische Tabelle ist auf den PROGMEM auslagerbar; es 
wird dabei AVR-SRAM gespart (ca. 200 Byte)

* neue Operatoren:
  * shl
  * shr
  * xor (nicht ^ wie vorgeschlagen, da ^ in Basic für Potenz steht...)
  * >=
  * <=
  * <>

* alternative Operatoren
  * für | geht auch or
  * für & geht auch and
  * für % geht auch mod

Die, im Quellcode-Archiv vorhandene Doku wurde entsprechend angepasst.

Grüße Uwe

von Roman65536 (Gast)


Lesenswert?

Uwe,

eine kleine anmerkung...

bei den vpeek,vpoke und auch bei den externen functions aufruffen...
Da gibt es eine moeglichkeit, einfacher die variablem wie auch 
funktionen zu definieren. und zwar macht man dies auch im Linux kernel 
so..
Dort werden "export" zugaengliche variablem und funktionen mit 
EXPORT_SYMBOL deklariert. Durch die macros von macros und macros, wird 
eine symbol tabelle automatisch erstellt. Diese ist zwar in einem 
reservierten segment, aber dies koennte man anderst umgehen. was denkst 
du ?? (hoffe du verstehst was ich meine :)

siehe dir http://lxr.linux.no/#linux+v2.6.34/include/linux/module.h#L199
mal an.

lg roman

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Hallo Roman,

ohne die Sache genau zu hinterblicken, denke ich aber dass es für die 
kleine Geschichte, wie der Basic-Interpreter sie ist, die Sache mit 
EXPORT_SYMBOL noch komplizierter ist.

Und noch eine 2.Sache kommt zum tragen, die ich ich vor Wochen mal in 
einem parallel Thread über die call-Funktion ausdiskutiert hatte --> ich 
müsste dazu die Quellen der zu exportierenden Funktionen und Variablen 
anpassen. Das genau möchte ich aber nicht...

Grüße & Danke Uwe

PS.: wobei die Sache aber schon interessant ist und vielleicht mal 
woanders zu gebrauchen ist (nur halt nicht auf Mikrocontrollern).

von TheMason (Gast)


Lesenswert?

@Roman0xffff und Uwe

Evtl. lässt sich mit dem Präprozessor die vpeek&vpoke fkt reinfach 
erweitern. Ich habe in einem anderen Thread etwas zu der einfachen 
Erweiterbarkeit/Wartung mittels Präprozessor schon was geschrieben.

Also wenns nur zur Compilierzeit sein muß und nicht zur laufzeit dann 
lässt sich das ganze recht einfach erweitern. Ich mache mal ein Beispiel 
dazu fertig. Vllt kann Uwe das ja bei sich mit aufnehmen.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

TheMason schrieb:
> Also wenns nur zur Compilierzeit sein muß und nicht zur laufzeit dann
> lässt sich das ganze recht einfach erweitern. Ich mache mal ein Beispiel
> dazu fertig. Vllt kann Uwe das ja bei sich mit aufnehmen.
>
ok, zeige mal her, wenn du soweit bist... Bzw. welches war der andere 
Thread?

Grüße Uwe

von roman65536 (Gast)


Lesenswert?

Uwe die sache ist gar nicht so schlimm...

kucke dir das wirklich mal an, hier ein "sampler" ;)

 278 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, 
loff_t *pos)
 279{
 280        ssize_t ret;
 281
 282        if (!(file->f_mode & FMODE_READ))
 283                return -EBADF;
..
..
..
 303        return ret;
 304}
 305
 306 EXPORT_SYMBOL(vfs_read);
 307

Die Function wird ganz normal deklariert, so wie es der interpreter 
braucht,
anschliessend wird per Macro die function in die funktions tabelle 
aufgenommen. das zu kompilier zeit .. so ala TheMason..

In dem Linux Kernel funzt das ganz relativ kompliziert ab. Den alle 
Symbole werden in eine Symbol section reingeschrieben. Diese kann man 
ganz normal erreichen, da sie in dem ld script definiert wird siehe:
__start___ksymtab = .;
                *(__ksymtab)
__stop___ksymtab = .;


Das ganze geht dann in die data section des kernels. Vor 2.4 tat man 
dies anderst, mit verlinkten listen... jedoch musste man alle funktionen 
die man exportieren moechte irgendwie dem kernel bekannt manche. Meist 
per init funktion vom modul oder device driver. mit dem macros ist es 
nun einfacher geworden..

Ich probiere was .. aber zb. die .fini9 bis .fini0 sectionen koennte man 
dafuer verwuergen :p

lg roman

von TheMason (Gast)


Angehängte Dateien:

Lesenswert?

So. Habe mal etwas gebastelt.

Eine auf der Original-Version von Adam Dunkels basierende Erweiterung. 
Ist noch nicht ganz fertig, aber vorab schonmal eine Zwischenversion.
Lässt sich aber für AVR compilieren und (scheint) im Simulator auch zu 
laufen. Allerdings eben ohne Hardware-Ansteuerung. Dafür aber schon mit 
(hoffentlich korrekten) Flash-Routinen (also das Schlüsselwörter nicht 
mehr zusätzlich RAM belegen).


Was kann die Erweiterung ?

- Schlüsselworte (und fkt) in einer Datei (basic_cfg.h)
- eigene Benutzerfunktionen (mit is zu 4 Parametern) "einhängbar"
- eigene Operatoren "einhängbar" (allerdings nur 1-Zeichen lang)
- Zugriff auf Variablen in C
- Zugriff auf Arrays in C
- Variablen, Arrays und Benutzerfunktionen lassen sich in Ausdrücken 
verwenden
- einfache Konfiguration in basic_cfg.h

Beispiel Funktionen stehen in der use-basic.c
Bei Fragen einfach melden.

Es ist wie gesagt nur eine Zwischenversion. Daher auch der 
Original-Datei-Name (uBasic-0.1.zip). Und noch nicht am lebenden AVR 
getestet.

von TheMason (Gast)


Lesenswert?

Nachtrag :

Die an die Benutzerfunktion übergebenen Datentypen können Zahlen bzw 
Ausdrücke oder Strings sein.

von TheMason (Gast)


Angehängte Dateien:

Lesenswert?

Hier eine erneute Version. Sollte auf AVR wie auf PC lauffähig sein.
Ich habe den Unterbau von Uwe verwendet (also die Eingabeaufforderung 
für die Befehle load, load x, run und list), und für die PC-Version 
Makros angelegt sodass die Funktionen usart.c auf dem PC verwendet 
werden können.
Viel Spaß beim ausprobieren.

von Roman65536 (Gast)


Lesenswert?

<zynismus on>
Man koennte doch den interpreter in ein Rom schiessen und anstatt bios 
im PC reinstecken :D damit waeren wir wieder ganz am Anfang. Back to the 
future..
<zynismus off>

@Mason koennstest du "^" veraendern und "xor" verwenden ?? Das ^ wird 
meistens im Basic fuer "hoch" verwendet, 2^2=4 5^2=25..

gruesse roman(2^16)-1 ;)

von Roman65536 (Gast)


Lesenswert?

eine frage ?? Mason..

du verwenderst ja so in etwa dein parser...
jetzt.. ein hypotetischer beispiel ok ??
ich moechte die expression erweiter um die ">=".. wie muss ich das 
anstellen ??

lg roman

von TheMason (Gast)


Lesenswert?

@roman (16^4)-1 :

Ich habe vor das man die Operatoren frei definieren kann. Im moment 
können Oepratoren nur 1 zeichen lang sein. Daher funktioniert auch ein 
<>, >=, <= nicht als Operator. Dasselbe gilt für and,or und xor.
Ich Bau das noch ein. Ist kein Ding. Hatte es nur noch nicht 
ausprogrammiert.

Das Problem liegt darin das nur in den Tokens TOKEN_CHAR im Abschnitt 
BASIC_TOKENS die Operatoren definiert werden können.
Die Zuordnung muß aber in TOKEN_TERM/EXPR/REL im Abschnitt TOKEN_OPS 
gemacht werden. Ich denke das werd ich wohl heute abend oder so 
einstellen können. Dann sind auch Operatoren wie mod, shl, shr, usw 
drin.


Wie meinst du "So in etwa verwendest du deinen Parser ?"
Mein Parser ist unabhängig vom uBasic-Strang (selbst wenn ich mir durch 
diesen Quellcode einiges aneignen konnte und schon einige Dinge 
dahingehend umgesetzt habe mir ein eigenes Basic zu schreiben)

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Roman65536 schrieb:
> <zynismus on>
> Man koennte doch den interpreter in ein Rom schiessen und anstatt bios
> im PC reinstecken :D damit waeren wir wieder ganz am Anfang. Back to the
> future..
> <zynismus off>

naja, soweit davon ist ja das Basic auf einem Mikrocontroller nicht 
entfernt, eigentlich fehlt doch nur noch eine vernünftige 
Eingabemöglichkeit für die Basic-Programme, deren dauerhafte 
Abspeicherung auf einem beschreibbaren Medium, z.B. SD-Card, und dann 
hast du doch fast einen Homecomputer, der vor 25 Jahren der Renner 
war...

OK, eine schicke Ausgabe auf einem Bildschirm oder Fernseher wäre auch 
noch schick, aber machbar... beweisen ähnliche Projekte...

Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

TheMason schrieb:
> Hier eine erneute Version. Sollte auf AVR wie auf PC lauffähig sein.
> Ich habe den Unterbau von Uwe verwendet (also die Eingabeaufforderung
> für die Befehle load, load x, run und list), und für die PC-Version
> Makros angelegt sodass die Funktionen usart.c auf dem PC verwendet
> werden können.
> Viel Spaß beim ausprobieren.

schwere Kost ;-), die man sich mal in Ruhe anschauen und ausprobieren 
muss (ich habe mir noch nie deine Parser angesehen, nur davon gehört, 
dass sie reichlich tricky sind...). Es ist nicht mehr viel von der 
Ursprungsversion übrig geblieben.

Zwei Dinge, die mir sofort aufgefallen sind und die ich nicht so gut 
finde:

Bei den Userfunktionen/-variablen gibt es jetzt keine klare syntaktische 
Trennung zwischen "Standard-Basic" und eben diesen. Deshalb hatte ich 
die Konstrukte mit call, vpeek und vpoke gewählt, um damit zum Ausdruck 
zu bringen, dass es externe Dinge sind, die eigentlich nicht 
Basic-Bestandteil sind.

Ich habe es noch nicht für einen AVR übersetzt und ausprobiert, muss ich 
mal in Ruhe machen, aber gefühlsmäßig könnte jetzt zuviel Overhead da 
sein, der mehr Resourcen des AVR okupiert...

Aber zweifellos eine interessante Sache, die es ermöglicht einfacher 
neue Befehle zu kreieren und einige schöne Ansätze aufzeigen.

Wie gesagt ich muss mal in Ruhe drüberschauen, vollständig verstehen und 
sehen, was ich adaptiere...

Grüße & Danke Uwe

von TheMason (Gast)


Lesenswert?

@uwe

In dem Thread AVR CP/M wird eine kleine schnuckelige Platform 
vorgestellt. Da werkelt ein AVR (MegaXX8) drauf und es ist noch ein 
128KB DRAM, eine SD-Card sowie ein FT232 drauf. Ich denke mit dieser 
Platform lässt sich bezüglich des Basics sehr viel machen. Also für 
lange Programme, für einen Editor usw wäre damit genug Platz. Habe dazu 
auch schon ein paar Ideen. Ich denke ich werde mit dieser Platform mal 
was in Richtung des uBasics veranstalten :-)

von Uwe B. (boerge) Benutzerseite


Lesenswert?

achso, noch eine Anmerkung zu den "Einzeichen-Befehlen" und den 
"Verwandten" ("<=", ">=", ...): ich habe in Abänderung vom Original in 
meiner Version die Verarbeitung der Keywörter vor die Suche nach 
Einzeichen-Befehlen gestellt, damit zuerst Keywörter (damit auch "<=" 
usw.) gefunden werden und dann erst Einzelbefehle ("<", ">", ...).

Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

TheMason schrieb:
> In dem Thread AVR CP/M wird eine kleine schnuckelige Platform
> vorgestellt. ...

ja kenne ich, war auch nur eine Anmerkung zu dem "Zynismus" von Roman... 
;-)

Uwe

von Roman65536 (Gast)


Lesenswert?

Die verwendung von den includes..ist zwar fuer den preprocessor schoen 
und nach dem gcc -E sieht es auch super aus. doch man(n) muss zugeben, 
die lesbarkeit leidet..

dh. moechte man den parser zb. erweitern, um eine binaere suche (den mit 
strcmp schnell was suchen, ist so eine sache), ist der code jetzt 
schwerer zu lesen. zum beispiel.. die vielen if's in singelchar, koennte 
man doch per map resp. tabelle und der *ptr waere index, schneller 
loessen als sich durch die vielen if's durch zu arbeiten.
bei der keywords... keywords sortieren und ueber eine hilfs tabelle fuer 
den anfangs buchstaben der keywords, an den effektiven keyword zu 
gelangen. Erst dann den strcmp durchfuehren. Die hilftabelle koennte ja 
schon hinweise beinhalten, das zb. kein keyword vorhanden ist der mit 
dem buchstaben "Z" anfaengt. ala..

key_tab['P']= &keywords[print];


Was mir auch vorschwebt im kopf.. zb. ein goto/gosub cache einzubauen.. 
den so wie die routinen jetzt arbeitet, sucht die jump_linenr von anfang 
an, bis die entsprechende linenr gefunden worden ist.  :)

lg roman(4^8)-2

von TheMason (Gast)


Lesenswert?

@roman 256^2

Es stimmt schon das es nicht soo schön lesbar ist, obwohl mit der 
richtigen Formatierung gehts einigermaßen.
Viel wichtiger finde ich eig. das man bei komplexeren Datengebilden mit 
Querverweisen diese automatisch Eintragen lassen kann, und damit die 
Daten immer konsistent sind. Ich denke da kann man sich eine ganze Menge 
Arbeit mit ersparen, vor allem eine ganze Menge Fehlersuche in 
verrutschen Datentupeln oder Enums die einfach in der Zeile verrutscht 
sind.

Binäre Suche wäre sicherlich deutlich schneller, aber ich denke weder 
mit Präprozessor, noch mit einfachen mitteln lässt sich das "mal eben" 
machen.
Die Tabellenstrukturen sind da ja schon aufwendiger. Und ich denke dann 
wäre die lesbarkeit vollends im A......

Das ein plattes strcmp nicht das optimalste ist ist klar :-)

Die Idee mit dem GOTO/GOSUB Cache habe ich auch, wobei ich denke das es 
evtl vllt sogar noch sinniger ist dem Basic-Interpreter die Tokens 
direkt zum Fressen vorzuwerfen. Also das ein Text bereits übersetzt ist 
(mit den notwendigen Informationen) und eben keine strcmp's und Suche 
nach Zeilennummern gemacht werden muß. Und so wie ich die Struktur des 
Basic-Interpreters verstanden hab müsste es sehr einfach sein da 
Umschalten zu können, da alle notwendigen Fkt in der tokenizer.c 
gekapselt sind. Diese müsste man eig. "einfach nur" austauschen und dann 
dürfte das ganze viiiieeeeel schneller gehen.
Den Ansatz werde ich mal weiter verfolgen. Evtl das dieser "Compiler" 
sogar auf einem AVR lauffähig ist (die Daten können ja auf SD-Karte 
geschrieben werden, und das übersetzte Programm von der Karte aus 
ausgeführt werden). Als Krönung wäre dann noch das man zu den 
Token-Informationen noch Informationen zum Quellcode selbst mit ablegt 
(z.b. Zeichenposition Token <-> Text). Dann hat man "relativ" leicht die 
Möglichkeit umfangreiche Debug-Möglichkeiten (mit Ausgabe des 
Zeileninhaltes usw) zu schaffen.
Aber das ist noch alles etwas Träumerei ;-)

von Roman65536 (Gast)


Lesenswert?

@theMason
Also so in etwa wie es anno domini der 8052 oder auch der C64'er basic 
glaube ich) tat ??
Der 8052er basic hat, die eingegebene zeile gleich zu tokens verarbeitet 
und nur so abgeschpeichert. Dafuer hat man die upper 128 von den 8 bits 
verwendet. Der "list" musste das dann interpretieren, was ja nicht soo 
schwer ist. jedoch fuer die goto/gosub, so wie es du schreibst brauchte 
man eine eine 2 pass loessung. den vorwaerts gerichtete goto/gosub's 
kennt man nicht von anfang an.

Was das andere angeht, mit preprocessor geht das evtl. gar nicht... 
jedoch .. die shell scripts verwanden laeute schreiben ja gern kleine 
scripts .. :)
btw. deine version funzt jetzt auch mit Linux 8)

roman(2^(32-16))-1

von TheMason (Gast)


Lesenswert?

@roman ((485*9)+4)*3*5

der C64 hat nur die Schlüsselwörter in Tokens übersetzt, der rest 
(Zahlen und Zeichen) wurden meine ich so Interpretiert.
Man kommt um 2 Pass nicht drum herum, aber ich denke der 
Geschwindigkeitsvorteil dürfte enorm sein (die Suche nach 
Schlüsselwörtern, das Parsen von Zahlen, das suchen nach Zeilennummern 
usw).

von Roman65536 (Gast)


Lesenswert?

der 8052er basic tat es aenlich.. jedoch die zeilen nummern waren binaer 
..

dem kann ich nur zustimmen... der cray unter den basic's :)

hihi...


btw.. habe gerade den goto cache ausgetestet (quick and very very dirty) 
.. geht super..

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Uwe Berger schrieb:
> Ich habe es noch nicht für einen AVR übersetzt und ausprobiert, muss ich
> mal in Ruhe machen, aber gefühlsmäßig könnte jetzt zuviel Overhead da
> sein, der mehr Resourcen des AVR okupiert...

hmm, diese Vermutung scheint sich zu bewahrheiten:

Ich habe mal die Version von TheMason für meine Test-AVR-Umgebung 
übersetzt und geflasht. Das Ergebnis ist nicht gut (unused mem):
--> nach Reset: 311 Byte
--> nach load 0: 311 Byte
--> nach run: 48 Byte!!!!
Das ist Ergebnis ist auch bei den anderen Programmen ähnlich.

Bei meiner letzten Version sieht es etwas anders aus:
--> nach reset: 395 Byte
--> nach load 0: 391 Byte (ein ungefähr vergleichbares Basic-Programm)
--> nach run: 379 Byte!!!!

... da wird zur Laufzeit des Interpreters zuviel SRAM verbraucht...!

Grüße Uwe

von TheMason (Gast)


Lesenswert?

Mmh,

der SRAM-Verbrauch rührt evtl (oder eher sehr wahrscheinlich) daher das 
der durch den Präprozessor generierte Typ recht viel RAM verbraucht. Bei 
anderen Einstellungen in der BASIC-CONFIG (Parameter 
MAX_USER_KEYWORD_LEN und MAX_USER_PARAMS) spielen bei dem "Verbrauch" 
des User-Datentyps, der in jeder Rekursion von "varfactor" lokal 
angelegt wird, eine enorme Rolle.
Da aber der Typ String als Übergabe-Parameter oftmals sinnvoll ist (z.b. 
bei LCD-Ausgaben) und Strings naturgemäß recht viel SRAM verbrauchen ist 
der Parameter MAX_USER_KEYWORD_LEN  MAX_USER_PARAMS  (Rekursionen der 
Ausdrücke) ein grobes Maß des SRAM Verbrauchs plus dem Overhead der 
durch die Erweiterung allgemein entsteht.
Würde man auf Strings verzichten, so wäre MAX_USER_KEYWORD_LEN = 2 und 
es wäre ein "moderater" Anstieg des Ressourcenverbrauchs.
Aber in Anbetracht der Features ist der erhöhte Ressourcenverbrauch 
denke ich (und hoffe ich :-)) gerechtfertigt. Dazu müsste man aber 
weitere "Messungen" vornehmen.
Das Ganze ist im Moment eher "auf die Schnelle" gemacht und nicht gerade 
100% ressourcenoptimiert.
Ursprünglich war auch nur die einfache Erweiterung der 
call-Schlüsselwörter bzw Schlüsselwörter generell "geplant", aber 
irgendwie hab ich mich in dem Interpreter "verbissen". Da gibts einfach 
zu viele Möglichkeiten ;-)

von Uwe B. (boerge) Benutzerseite


Lesenswert?

TheMason schrieb:
> Aber in Anbetracht der Features ist der erhöhte Ressourcenverbrauch
> denke ich (und hoffe ich :-)) gerechtfertigt.

eigentlich nicht, da es auf einem AVR, für den ich den Interpreter 
vorgesehen habe, kronischen Platzmangel im SRAM gibt. Der Interpreter 
soll ja eigentlich nur Beiwerk zu anderen Firmwarebestandteilen sein...

Für einen Basic-Interpreter, der nicht auf einer Plattform mit 
beschränkten Resourcen laufen soll, hat deine Lösung natürlich schon 
einen gewissen Charme. Aber wie gesagt, dass ist eigentlich nicht mein 
Anliegen.

Mal zur Diskussion über einen möglichen goto/gosub-Cache:
Für For-Next-Schleifen gilt nebenbei ähnliches.
Ich befürchte solch ein Cache frisst weitere Resourcen im SRAM. 
Zumindestens für gosub und for-next bietet sich eine andere Lösung an! 
Statt der Basic-Zeilennummer, könnte man auch den entsprechenden Pointer 
auf den Basic-Quelltext abspeichern und dorthin bei return bzw. next 
(zurück)springen.

Für goto-Anweisungen hat man sowieso ein Problem, weil man nicht weis, 
ob es ein Sprung nach vorn oder zurück ist. Man müsste im Vorfeld das 
ganze Basic-Programm analysieren und entsprechenden Einsprungstellen 
abspeichern, was wieder auf Kosten der Performance und der Resourcen 
gehen würde...

Grüße Uwe

von TheMason (Gast)


Lesenswert?

@Uwe

Ich geb dir Recht das der SRAM Verbauch immer etwas kniffelig ist, bzw 
die Gratwanderung zwischen Features und Performance.
Aber in einem kleinen AVR (512-1024Byte SRAM) ist der Interpreter 
ohnehin schon etwas "übertrieben", da dann nur noch wenig SRAM für die 
eigentlichen Firmwarefunktionen übrigbleibt.
Und dadurch das der Basic-Code nur aus dem SRAM ausgeführt werden kann 
ist bei kleinen AVR's ohnehin schnell Schicht im Schacht, was die 
Programmlänge angeht.
Ich denke mein Ansatz bei dem Basic ist eher für Größere AVR's (ab 
Mega16/32 mit 1-16kB RAM) wirklich sinnvoll einsetzbar, oder aber für 
ARMs usw.

@All

Ich habe mal mit dem "Compiler"-Ansatz etwas ausprobiert. Also das der 
Interpreter auch in der Lage ist Basic-Code zu "compilieren". Dabei 
werden in einem ersten Schritt die Goto/Gosub-Adressen ermittelt, und im 
zweiten Schritt die Tokens in ein Byte-Array gepackt (und bei Goto/Gosub 
die Stelle im Byte-Code angegeben). Weiterhin lässt sich der Byte-Code 
auch mit (nahezu) den gleichen Routinen ausführen. Zeitmessungen und 
SRAM-Verbräuche habe ich noch nicht ermittelt. Aber ich denke das man 
mit dem compilierten Byte-Code schon recht gute ergebnisse erzielen kann 
was SRAM-Verbrauch angeht. Von der Geschwindigkeit ganz zu schweigen.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

TheMason schrieb:
> Und dadurch das der Basic-Code nur aus dem SRAM ausgeführt werden kann
> ist bei kleinen AVR's ohnehin schnell Schicht im Schacht, was die
> Programmlänge angeht.
> Ich denke mein Ansatz bei dem Basic ist eher für Größere AVR's (ab
> Mega16/32 mit 1-16kB RAM) wirklich sinnvoll einsetzbar, oder aber für
> ARMs usw.

meine Testumgebung ist ein Mega16, immerhin sind da noch ca. 300 Byte 
Platz. Damit kann man noch eine Menge anfangen...

Mit dem Basic-Code im SRAM hast du natürlich recht, aber einer der 
nächsten geplanten Schritte ist, das Basic-Programm von einer SD-Card 
(zeichenweise) einzulesen --> in tokenizer.c müssten dazu die Zugriffe 
auf die beiden Pointer (ptr und nextptr) entsprechend angepasst werden.

Die ganze Geschichte mache ich eigentlich auch nur, weil ich in der 
Firmware zu meinem NET-I/O mit Add-On-Board eine Art Jobstarter (ala 
Cron) schreiben will, bei dem die auszuführenden Jobs halt Scripte auf 
der SD-Card sein sollen.

Grüße Uwe

von Roman65536 (Gast)


Lesenswert?

Ehhh...

Wenn es aber um limitierten resourcen geht, dann ist evtl. dieser basic 
interpreter so oder so "zu gross". Es gab einmal vor lange lange lange 
zeit, einen interpreter.. und der source code dazu ist 1536 bytes gross 
...
er kann aber so ziemlich alles was Dunkels interpreter kann..

ok Ihr werdet lachen wo man so was findet, obfuscated C aber schickt man 
den code durch den preprocessor und ein bisschen formartierung, sieht 
der code ganz ok aus und ziemlich schlau..

http://www0.us.ioccc.org/1990/dds.hint

lg roman0x1000-1

von TheMason (Gast)


Lesenswert?

@Uwe

>das Basic-Programm von einer SD-Card (zeichenweise) einzulesen

Das ist ebenfalls eine Erweiterung die ich noch im Kopf habe. Zudem soll 
es dann auch möglich sein den Compilierten Byte-Code von SD-Karte 
auszuführen. Dann kann man (abgesehen von den 512 Byte für den SD-Karten 
Buffer) auch wieder etwas RAM freischaufeln.

@Roman 0x10000-1

>ist evtl. dieser basic interpreter so oder so "zu gross"

Daher auch der Ansatz möglichst viele Funktionen die sich "relativ" 
einfach nachrüsten lassen unterzubringen. Es braucht dann zwar mehr 
Ressourcen, aber kann dann auch entsprechend mehr.

Ich werde bei meiner bestehenden Version noch einen Compiler-Schalter 
einbauen, mit dem man die zusätzliche Funktionalität (C-Routinen, 
C-Variablen, C-Arrays) abschalten kann um so das ganze flexibel anpassen 
zu können.

von Roman65536 (Gast)


Lesenswert?

Hier noch mein goto/gosub/for/next quick an very dirty cache.. ohne es 
zu wissen, es cached auch die for/next :)
Bitte nicht erschiessen wegen dem 256 array.. war ja nur ein test auf 
linux.

ubasic.c :
...
int ended;

extern char *ptr, *nextptr;

char *goto_cache[256];
char *goto_cachen[256];

int  expr(void);
void line_statement(void);
void statement(void);
int get_parameters(T_USER_FUNC_DATAS *params, int numparams, int next);
int get_arrayindex (void);
void accept(int token);

/*---------------------------------------------------------------------- 
-----*/
void ubasic_init(const char *program)
{

 int a;
  for(a=0;a<256;a++) goto_cache[a]=goto_cachen[a]=(char *)0; //init 
cache..
  program_ptr = program;
  for_stack_ptr = gosub_stack_ptr = 0;
  tokenizer_init(program);

...

/*---------------------------------------------------------------------- 
-----*/
void jump_linenum(int linenum)
{


  if(goto_cache[linenum % 255] != 0) {
    ptr=goto_cache[linenum % 255];
    nextptr=goto_cachen[linenum% 255];
    printf("cache hit for %d %x %x\n",linenum,ptr,nextptr);
       tokenizer_init(ptr);
    return;
  }

  tokenizer_init(program_ptr);
  while(tokenizer_num() != linenum) {
    do {
      do {
        tokenizer_next();
        if (tokenizer_token() == TOKENIZER_ERROR)
        {
          FATAL_ABORT();
        }
      } while(tokenizer_token() != TOKENIZER_CR &&
        tokenizer_token() != TOKENIZER_ENDOFINPUT);
      if(tokenizer_token() == TOKENIZER_CR) {
        tokenizer_next();
      }
    } while(tokenizer_token() != TOKENIZER_NUMBER);
    DEBUG_PRINTF("jump_linenum: Found line %d\n", tokenizer_num());
  }
   if(goto_cache[linenum % 255] == 0) {
    goto_cache[linenum %255]=ptr;
    goto_cachen[linenum%255]=nextptr;
    printf("cache fill %d %x %x\n",linenum,ptr,nextptr);
   }
}


hier noch der output (auf linux) :

AVR-uBasic-Interpreter; Uwe Berger, 2010
Compiliert am Jun 30 2010 um 14:55:28

>load 2
load 2

Programm 2 geladen.

>run
run

1
cache fill 20 804b192 804b194
2
cache hit for 20 804b192 804b194
3
cache hit for 20 804b192 804b194
4
cache hit for 20 804b192 804b194
5
cache hit for 20 804b192 804b194
6
cache hit for 20 804b192 804b194
7
cache hit for 20 804b192 804b194
8
cache fill 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
30
cache fill 80 804b1ef 804b1f1
31
cache hit for 80 804b1ef 804b1f1
32
cache hit for 80 804b1ef 804b1f1
33
cache hit for 80 804b1ef 804b1f1
34
cache hit for 80 804b1ef 804b1f1
35
cache hit for 80 804b1ef 804b1f1
36
cache hit for 80 804b1ef 804b1f1
37

>list
list

10 for i = 0 to 7
20 print adc [i]
30 next i
40 for i = 0 to 7
50 adc [i] = 30 + i
60 next i
70 for i = 0 to 7
80 print adc [i]
90 next i
99 end

>


lg roman

von TheMason (Gast)


Lesenswert?

@Roman 0b1111111111111111

Ich glaube den "goto_cachen" kannst du dir glaube ich sparen indem du 
nach dem setzen des zeigers ein "tokenize_next()" aufrufst.
Zumindest hab ich das so verstanden.
Das setzen des Zeigers holt noch nicht das aktuelle Token ab, und so 
kommt der Interpreter durcheinander, denn bei jedem accept muß das 
aktuelle Token vorhanden sein (also der ptr-zeiger schon auf das nächste 
Token stehen).

von Roman65536 (Gast)


Lesenswert?

@Mason wie gesagt quick and dirty..
aber habe mich auch schon gefragt.. muss den code noch durcharbeiten 
fuer was der nextptr ist.. evtl. hast du recht. waere cool ..

mit dem array resp. hash bin ich auch nicht wirklich gluecklich..


lg roman0177777

von Roman65536 (Gast)


Lesenswert?

@Mason


nicht einmal das.. der tokenizer_init macht das schon :D

hier ohne goton

/*---------------------------------------------------------------------- 
-----*/
void jump_linenum(int linenum)
{


  if(goto_cache[linenum % 255] != 0) {
    ptr=goto_cache[linenum % 255];


       tokenizer_init(ptr);
      printf("cache hit for %d %x %x\n",linenum,ptr,nextptr);
    return;
  }

  tokenizer_init(program_ptr);
  while(tokenizer_num() != linenum) {
    do {
      do {
        tokenizer_next();
        if (tokenizer_token() == TOKENIZER_ERROR)
        {
          FATAL_ABORT();
        }
      } while(tokenizer_token() != TOKENIZER_CR &&
        tokenizer_token() != TOKENIZER_ENDOFINPUT);
      if(tokenizer_token() == TOKENIZER_CR) {
        tokenizer_next();
      }
    } while(tokenizer_token() != TOKENIZER_NUMBER);
    DEBUG_PRINTF("jump_linenum: Found line %d\n", tokenizer_num());
  }
   if(goto_cache[linenum % 255] == 0) {
    goto_cache[linenum %255]=ptr;

    printf("cache fill %d %x %x\n",linenum,ptr,nextptr);
   }
}


>load 3
load 3

Programm 3 geladen.

>load 2
load 2

Programm 2 geladen.

>run
run

1
cache fill 20 804b192 804b194
2
cache hit for 20 804b192 804b194
3
cache hit for 20 804b192 804b194
4
cache hit for 20 804b192 804b194
5
cache hit for 20 804b192 804b194
6
cache hit for 20 804b192 804b194
7
cache hit for 20 804b192 804b194
8
cache fill 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
cache hit for 50 804b1bf 804b1c1
30
cache fill 80 804b1ef 804b1f1
31
cache hit for 80 804b1ef 804b1f1
32
cache hit for 80 804b1ef 804b1f1
33
cache hit for 80 804b1ef 804b1f1
34
cache hit for 80 804b1ef 804b1f1
35
cache hit for 80 804b1ef 804b1f1
36
cache hit for 80 804b1ef 804b1f1
37

der nextptr wird schon von tokenizer_init() richtig gesetzt :)

jupii

von TheMason (Gast)


Lesenswert?

Achso ja ...

Sehs gerad. Der tokenizer_init ruft ja tokenizer_next auf. Von daher 
funktionierts so.

von TheMason (Gast)


Angehängte Dateien:

Lesenswert?

Wie angedroht mal eine neue Version.
Ich hoffe das es für dich ok geht Uwe, wenn ich den Thread "entführe". 
Wenn nicht mache ich einen neuen Thread dazu auf.

Also ich habe mal ein bissl investigative Recherche an meinem Quellcode 
betrieben und so einige Parametrierbar gemacht, was den 
Speicherverbrauch (Flash/SRAM/Heap) angeht.

Der reine Interpreter (ohne die Erweiterungen der C-Fkt, C-Variablen, 
C-Arrays) benötigt (mit printf, welches man auch noch wegparametrieren 
kann)
 - 4768 Bytes Flash
 - 132 Byte RAM (da lässt sich einiges per Gosub/For-Stack Tiefe 
konfigurieren)

Mit Erweiterungen (ohne die Funktionen selbst, bzw mit nur einer 
Dummy-Fkt) benötigt der Interpreter :
 - 5844 Bytes Flash
 - 154 Byte RAM (hier wird allerdings der größte Teil für die 
Parameter-Übergabe auf dem Stack benötigt, das macht den allergrößten 
Teil aus, daher ist bei entsprechender Konfiguration auch noch einiges 
ein Einsparpotential drin).

Der Interpreter ohne Erweiterungen, aber mit Compiler :
 - 6182 Byte
 - 154 Byte RAM (der Buffer für den Compiler ist hier noch nicht mit 
eingerechnet)

Der Interpreter mit Erweiterungen und Compiler :
 - 7340 Byte
 - 180 Byte RAM

Der Compiler lässt sich folgendermaßen benutzen :

Erst das Programm laden mit load (x), dann "compile" eingeben, dabei 
wird der Byte-Code angezeigt, und mit "runc" lässt sich der Compilierte 
Code ausführen.
Im moment muß wenn man ein anderes Programm Compilieren will, dieses 
erst mit run ganz normal ausgeführt werden (ist noch ein kleiner Bug, da 
der runmode beim erneuten compilieren noch auf "RM_COMPILE" steht, und 
nur im Text-Modus Compiliert werden kann.
Es ist noch nicht alles getestet. So funktioniert das Beispielprogramm 
Nr 2 als Kompilat noch nicht.
Aber für einen ersten Eindruck denke ich ist es ausreichend.
Ich denke mit dem Ansatz lässt sich einiges anstellen. Zumal man 
theoretisch ein komplettes Entwicklungssystem (wenn auch recht 
eingeschränkt, dadurch das das SRAM eben sehr knapp ist für größere 
Programme) damit realisieren kann.
Die nächste Erweiterung ist die von Uwe schon angesprochene, und zwar 
das das Programm (Text oder Byte-Code) nicht unbedingt im RAM stehen 
muß.
Dazu wird es eine Funktion (bzw mehrere Funktionen) geben mit dem man 
das aktuelle Zeichen/Byte auslesen kann sowie die aktuelle Position 
lesen und setzen kann. Damit sollten die Grundvoraussetzungen für 
flexibles Speicherhandling geschaffen werden. Allerdings wird der 
Interpreter im Text-Modus dadurch nochmal erheblich langsamer (für jedes 
Zeichen muß eine Fkt aufgerufen werden, die je nach Quelle z.b. erst 
noch einen neuen Sektor von der SD-Karte lesen muß, usw).
Viel Spaß beim testen. Und ich hoffe Uwe ist nicht böse das ich den 
Thread etwas entführt hab. Aber das Thema ist ja auch mal sehr 
interessant.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

TheMason schrieb:
> Ich hoffe das es für dich ok geht Uwe, wenn ich den Thread "entführe".
> Wenn nicht mache ich einen neuen Thread dazu auf.

ich denke es ist sinnvoll, wenn wir hier den Thread aufsplitten, da 
deine Version in Richtung "Compiler" geht und (fast) nichts mehr mit 
meiner Ursprungsversion zu tun hat.

Trotzdem finde ich deine Geschichte/Ansätze schon interessant und werde 
einige deiner Ideen überdenken und vielleicht in meiner 
Interpreter-Version übernehmen.

Aber wie schon oben angedeutet, mein Ziel ist es eine resourcenschonende 
Version (vorallem SRAM) eines Interpreters zu implementieren, um diesen 
in bestehende Firmware integrieren zu können. Dabei steht z.B. das 
Laufzeitverhalten für mich nicht an erster Stelle (obwohl in der 
kommenden Version zwei Verbesserungen dazu eingebaut sind...).

Grüße & Danke Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

... und wie gerade angedroht, auf meiner entsprechenden Projektseite 
(http://bralug.de/wiki/UBasic-avr) ist eine neue Version des 
Basic-Interpreters verfügbar. Die Änderungen betreffen hauptsächlich 
interne Dinge:

* print-Befehl: man kann jetzt Ausdrücke auch klammern
* print-Befehl abwählbar
* gosub jetzt auch in if-then-else im then-Zweig möglich (war ein Bug)
* for-next, gosub: Rücksprung nicht via Zeilennummer, sondern 
Textpointer
* zur Laufzeitmessung von Basic-Programmen wurde ein entsprechender 
Befehl in main.c eingebaut

Grüße Uwe

von TheMason (Gast)


Lesenswert?

@Uwe

>Trotzdem finde ich deine Geschichte/Ansätze schon interessant und werde
>einige deiner Ideen überdenken und vielleicht in meiner
>Interpreter-Version übernehmen.

Mach das. Für Fragen stehe ich gerne zur Verfügung.

>Aber wie schon oben angedeutet, mein Ziel ist es eine resourcenschonende
>Version (vorallem SRAM)

Daher habe ich ja noch nachträglich Compiler-Schalter eingebaut. Um eben 
ressourcenfressende Routinen wie die Benutzer-Erweiterungen ausschalten 
zu können. Die Erweiterbarkeit ähnlich wie mit deinem Call-Befehl lässt 
sich bei mir ja auch implementieren, und somit ressourcensparende 
Erweiterungen dennoch nutzen. Von daher ist mein Code denke ich im 
ressourcenverbrauch deinem recht ähnlich wenn man bei mir die 
USER_EXTENSIONS und den USES_COMPILER Schalter weglässt.

>ich denke es ist sinnvoll, wenn wir hier den Thread aufsplitten,

Diesem Wunsch werde ich nachkommen :-)
Aber ich denke es ist sinnvoll sich über die beiden Threads 
auszutauschen. Und wenns ok ist kann man sich die Features ja 
gegenseitig implementieren. Sprich wenn du noch eine Verbesserung oder 
Bugfixing hast das ich diese in meinem übernehme. Oder eben umgekehrt.

Kleiner Tipp noch am Rande zum Thema ressourcensparen ...
Ich hab noch nicht in deine aktuelle Version reingeschaut, aber in 
meiner aktuellen Version hab ich die Tokens als char behandelt (über das 
define TOKEN) statt als int. Dadurch lassen sich auch nochmal ein paar 
zig Bytes Flash und ein paar Bytes auf dem Stack einsparen. Zudem wird 
der Interpreter noch ein kleines Itzken schneller.

von Rene B. (themason) Benutzerseite


Lesenswert?

Ich habe mal einen Parallel-Thread aufgemacht.
Den Link kann ich noch nicht posten da ich den Thread im falschen 
Unterforum erstellt habe. Ich habe die Admins bereits gebeten den Thread 
hierhin zu schubsen. Einen Link werde ich (wenns genehm ist) ebenfalls 
noch posten, da die beiden Threads ja schon eine gewisse Ähnlichkeit 
haben (zumindest die gemeinsame Basis des Quellcodes von Adam Dunkels 
Interpreter) und ich denke das sich beide Projekte ergänzen können.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Rene Böllhoff schrieb:
> Ich hab noch nicht in deine aktuelle Version reingeschaut, aber in
> meiner aktuellen Version hab ich die Tokens als char behandelt (über das
> define TOKEN) statt als int. Dadurch lassen sich auch nochmal ein paar
> zig Bytes Flash und ein paar Bytes auf dem Stack einsparen. Zudem wird
> der Interpreter noch ein kleines Itzken schneller.

... habe ich gerade mal ausprobiert:
* weniger Speicher ja, aber nur ein paar Byte
* schneller: erstaunlicherweise wird er langsamer...

Grüße Uwe

von Roman65536 (Gast)


Lesenswert?

@Uwe,

Kannst du bitte ein beispiel mit den for-next, gosub als textpointer 
hinposten ??
Und noch eine Frage.. wo ist der kleine tcl/tk script ?? hat es nicht in 
den tar-ball geschaft ??

lg roman

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Roman65536 schrieb:
> Kannst du bitte ein beispiel mit den for-next, gosub als textpointer
> hinposten ??

es handelt sich nur um eine interne Verbesserung: bei next 
(for-Schleife) bzw. return (gosub) wird nicht mehr das Programm von vorn 
neu geparst bis die entsprechende Zeilennummer ansteht, sondern es wird 
sich der entsprechende Zeiger auf die Basic-Programmstelle gemerkt und 
dann direkt dortin gesprungen.

Roman65536 schrieb:
> Und noch eine Frage.. wo ist der kleine tcl/tk script ?? hat es nicht in
> den tar-ball geschaft ??

in meinem privaten CVS gibt es noch das Script ;-)... Es funktioniert 
noch nicht, wie es soll und eigentlich habe ich auch keine Lust mehr 
daran Zeit zu verschwenden. Deshalb habe ich es aus dem Archiv 
rausgenommen. Es war eigentlich auch nur für komfortableres Testen 
vorgesehen, bis ich dann auf die Idee kam, meine "Testsuite" via 
ubasic_tests.h in den FLASH zu brennen... Warum hast du Interesse an dem 
Tcl/Tk-Ding?

Grüße Uwe

von roman65536 (Gast)


Lesenswert?

@uwe

hmm.. interessant.. dh. es koennte auch evtl. ganz ohne zeilen # gehen 
??
Wie sieht es aus mit den goto's die waeren doch auch ein Kandidat um 
sich diese waerend dem parsen zu merken.

Ach ja.. in meine Version.. aendere ich jeweils das variablen array auf 
short, ich bin es mir gewohnt von dem mini basic von Z80, M68k und auch 
von dem Z8, das man variablen bis 2^15 benuetzen kann :)

Warum den tcl/tk ?? hmm.. mit gefaellt dir Idee.. daraus koennte man 
noch mehr machen. Den zb. ich moechte eines tages ein basic computer 
bauen so ala ehh.. wie hiess das DDR ding schon wieder (sollte nicht 
abwertend sein) mit dem meine kleine auch etwas tun kann. zb. einfache 
Grafiken oder so was wie eine Schildkröte ansteuern oder files 
laden/saven auf dem host system.
Dh. tcl/tk dazu benuetzen um die Daten zu multiplexen, resp. 
packetizieren da man ja nur eine serielle Schnittstelle hat.


lg roman

von Roman65536 (Gast)


Lesenswert?

@uwe,


wenn ich so jetzt den interpreter so anschaue.. so was wie dein 
for_stack, resp. gosub stack koennte man auch fuer den goto einbauen ?? 
das es nicht viel speicher braucht, (ich meine, mein goto cache geht 
ganz gut fuer linux, aber fuer mcu.. neee..) wie waere es mit eine goto 
liste ?? ala for_stack oder gosub_stack ?? schon mit 8 entries kommt man 
ganz schnell weit :)




ubasic.c :
...
...
static struct for_state for_stack[MAX_FOR_STACK_DEPTH];
static int for_stack_ptr;


struct goto_list {
 const char *next_line_ptr;
 int line;
 };

static struct goto_list goto_lists[MAX_GOTO_LIST_DEPTH];
static int goto_list_ptr;

static int variables[MAX_VARNUM];
 ..
...
..




/*---------------------------------------------------------------------- 
-----*/
static void
jump_linenum(int linenum)
{
  int tmp;
  for(tmp=0;tmp < goto_list_ptr;tmp++)
    {
      if(goto_lists[tmp].line==linenum) {
  jump_to_prog_text_pointer(goto_lists[tmp].next_line_ptr);
  return;
      }
    }
  tokenizer_init(program_ptr);
  while(tokenizer_num() != linenum) {
    do {
      do {
  tokenizer_next();
      } while(tokenizer_token() != TOKENIZER_CR &&
        tokenizer_token() != TOKENIZER_ENDOFINPUT);
      if(tokenizer_token() == TOKENIZER_CR) tokenizer_next();
    } while(tokenizer_token() != TOKENIZER_NUMBER);
    DEBUG_PRINTF("jump_linenum: Found line %i\r\n", tokenizer_num());
  }
  if(goto_list_ptr < MAX_GOTO_LIST_DEPTH)
    {
      goto_lists[goto_list_ptr].next_line_ptr=get_prog_text_pointer();
      goto_lists[goto_list_ptr].line=linenum;
      goto_list_ptr++;
    }
}



lg roman

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Hallo Roman,

> hmm.. interessant.. dh. es koennte auch evtl. ganz ohne zeilen # gehen
> ??
>
naja, spätestens beim gosub müsste man sich etwas einfallen lassen! Man 
müsste dann Prozedur-Namen o.ä. einführen... Und bei goto irgendwelche 
Namen für Sprung-Marken. Zusätzlich wäre es dann sinnvoll soetwas wie {} 
für Funktionsblöcke einzuführen... Das würde dann also nach VB aussehen. 
Ich bin eigentlich ganz zufrieden, wie es jetzt ist.

> wenn ich so jetzt den interpreter so anschaue.. so was wie dein
> for_stack, resp. gosub stack koennte man auch fuer den goto einbauen ??
>
theoretisch hast du recht, hatte ich auch schon überlegt. Aber irgendwie 
ist der Aufwand dafür zu hoch, denn die Wahrscheinlichkeit, dass in 
(meinen geplanten) Basic-Programmen sehr viele Loops zu immer der selben 
Goto-Einsprungzeile gemacht werden, dürfte realtiv gering sein. Da 
bringt das "Vorübersetzen", wie es TheMason in seiner Version macht, 
schon mehr. Dabei könnte man gleich den Cache aufbauen und dann nur noch 
mit diesen Pointern direkt arbeiten.

> wie hiess das DDR ding schon wieder
>
ach, da gab es einige (die ich auch selbst mal hatte...) KC85/x, KC87, 
Z1013, ...

> Dh. tcl/tk dazu benuetzen um die Daten zu multiplexen, resp.
> packetizieren da man ja nur eine serielle Schnittstelle hat.
>
was meinst du damit?

Ich hatte das Tcl-Script eigentlich nur dafür vorgesehen, mehrere 
Basic-Programme auf dem PC zu verwalten und via serieller Schnittstelle 
zum MC zu senden und die Ausgaben wieder zurück zu bekommen. Eigentlich 
ist das Script fast fertig, irgendwie scheitere ich allerdings derzeit 
an der seriellen Übertragung selbst, weil ich wahrscheinlich die 
Schnittstelle beidseitig auf eine vernünftige Flusskontrolle umschalten 
müsste. Die derzeitige Version verschluckt u.a. ab und zu ein paar 
Zeichen....

Kannst du in Tcl programmieren?

Grüße Uwe

von Roman65536 (Gast)


Lesenswert?

@uwe

hast du die ergaenzungen mit dem goto buffer angeschaut ??
ist nicht viel code (resp. konfigurierbar)  ein #if mehr spielt doch 
keine rolle und bringt schon viel..

Nun ja wenn deine version deinen vorstellungen entspricht ist es ok.
Ich dachte eher, dass es eher in die richtung general purpose Basic 
geht,
wo man leider nicht in voraus weiss, wie viele goto's daher kommen.
Ich dachte da an ehh.. Papi Computer fuer meine kids. kleine tastatur 
fuer kleine haende und ein zwei oder vier linien LCD display. Aber 
wichtig selber gemacht.. mein 8 jaehrige hat schon am geschmack von 
Loetzinn gerochen :)

tcl.. na ja .. wenn der syntax nicht so verwirrend waere .. es gibt 
bessere hirschen als mich. wie du gesehen hast, ich kann es 
buchstabieren :D

lg roman
PS: tja ich komme zwar auch aus der robotron ecke.. oder wie die auch 
alle geheisen haben.. magyartron, polskitron, baerentron, skodatron ;) 
dann schon lieber Tron 8-D

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

Roman65536 schrieb:
> hast du die ergaenzungen mit dem goto buffer angeschaut ??
> ist nicht viel code (resp. konfigurierbar)  ein #if mehr spielt doch
> keine rolle und bringt schon viel..
>
naja, Frage ist ja immer, wieviel goto-Befehle treten in dem 
Basic-Programm auf und wieviel unterschiedliche Zeilennummern gibt es 
als Sprungziele.... Ich bin noch am überlegen, ob ich vielleicht doch 
etwas einbaue und spätestes beim zweiten Ansprung der gleichen 
Zeilennummer via besagten Textpointer geht, was man via Config 
zuschalten kann, mal sehen...

Nebenbei, es gibt noch einen weiteren Performance-Fresser: an einigen 
Stellen in ubasic.c wird zum einen das Zeilenende oder, noch extremer 
eine bestimmte Zeilennummer gesucht. Dabei wird immer tokenizer_next() 
verwendet, also jedes einzelne Elemente einzeln geparst (ohne eine 
Aktion auszuführen). Da werde ich demnächst auch nochmal ansetzen...

Grüße Uwe

von TheMason (Gast)


Lesenswert?

@Uwe

>Dabei wird immer tokenizer_next() verwendet, also jedes einzelne Elemente 
>einzeln geparst (ohne eine Aktion auszuführen).

Das ist mir auch schon aufgefallen. Ich denke da ist der größte 
Ressourcenfresser (was die Zeit angeht). Im Prinzip muß man ja nur nach 
\n suchen und danach muß dann eine Zahl kommen. Das tokenizer_next () 
ist wahrscheinlich nur eine bequemlichkeit von Adam gewesen, weils am 
einfachsten zu implementieren war/ist.

von Roman65536 (Gast)


Lesenswert?

Jungs,

ich habe da was getested, mit dem profiling..

ein einfaches prg:

10 for i = 1 to 100\n\
15 for n = 1 to 100\n\
20 gosub 100\n\
30 next n\n\
30 next i\n\
40 end\n\
100 print n,i \n\
105 return\n\


 gprof main
Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ns/call  ns/call  name
100.00      0.01     0.01   181242    55.17    55.17  get_next_token
  0.00      0.01     0.00   392176     0.00     0.00  tokenizer_token
  0.00      0.01     0.00   231645     0.00     0.00  tokenizer_finished
  0.00      0.01     0.00   151242     0.00    55.17  tokenizer_next
  0.00      0.01     0.00   130827     0.00     0.00  singlechar
  0.00      0.01     0.00   121110     0.00    55.17  accept
  0.00      0.01     0.00    50411     0.00     0.00  tokenizer_num
  0.00      0.01     0.00    40301     0.00     0.00 
ubasic_get_variable
  0.00      0.01     0.00    40202     0.00     0.00  Check_for_data
  0.00      0.01     0.00    40202     0.00   248.74  line_statement
  0.00      0.01     0.00    40202     0.00   193.57  statement
  0.00      0.01     0.00    40202     0.00     0.00  ubasic_finished
  0.00      0.01     0.00    40202     0.00   248.74  ubasic_run
  0.00      0.01     0.00    40202     0.00     0.00  usart_is_receive
  0.00      0.01     0.00    30201     0.00     0.00 
tokenizer_variable_num
  0.00      0.01     0.00    30000     0.00    55.17  tokenizer_init
  0.00      0.01     0.00    29998     0.00    55.17 
jump_to_prog_text_pointer
  0.00      0.01     0.00    20202     0.00    55.17  expr
  0.00      0.01     0.00    20202     0.00    55.17  factor
  0.00      0.01     0.00    20202     0.00    55.17  term
  0.00      0.01     0.00    20000     0.00    55.17  varfactor
  0.00      0.01     0.00    10201     0.00     0.00 
ubasic_set_variable
  0.00      0.01     0.00    10102     0.00     0.00 
get_prog_text_pointer
  0.00      0.01     0.00    10100     0.00   165.52  next_statement
  0.00      0.01     0.00    10000     0.00   220.87  gosub_statement
  0.00      0.01     0.00    10000     0.00    55.35  jump_linenum
  0.00      0.01     0.00    10000     0.00   275.87  print_statement
  0.00      0.01     0.00    10000     0.00   110.35  return_statement
  0.00      0.01     0.00      101     0.00   386.22  for_statement
  0.00      0.01     0.00       18     0.00     0.00  usart_receive_char
  0.00      0.01     0.00        3     0.00     0.00  usart_read_line
  0.00      0.01     0.00        1     0.00    55.17  end_statement
  0.00      0.01     0.00        1     0.00     0.00  load_from_flash
  0.00      0.01     0.00        1     0.00    55.17  ubasic_init

 %         the percentage of the total running time of the
time       program used by this function.

cumulative a running sum of the number of seconds accounted
 seconds   for by this function and those listed above it.

 self      the number of seconds accounted for by this
seconds    function alone.  This is the major sort for this
           listing.

calls      the number of times this function was invoked, if
           this function is profiled, else blank.

 self      the average number of milliseconds spent in this
ms/call    function per call, if this function is profiled,
     else blank.

 total     the average number of milliseconds spent in this
ms/call    function and its descendents per call, if this
     function is profiled, else blank.

name       the name of the function.  This is the minor sort
           for this listing. The index shows the location of
     the function in the gprof listing. If the index is
     in parenthesis it shows where it would appear in
     the gprof listing if it were to be printed.


         Call graph (explanation follows)


granularity: each sample hit covers 4 byte(s) for 100.00% of 0.01 
seconds

index % time    self  children    called     name
                                                 <spontaneous>
[1]    100.0    0.00    0.01                 main [1]
                0.00    0.01   40202/40202       ubasic_run [4]
                0.00    0.00       1/1           ubasic_init [20]
                0.00    0.00   40202/40202       usart_is_receive [29]
                0.00    0.00   40202/40202       ubasic_finished [28]
                0.00    0.00       3/3           usart_read_line [34]
                0.00    0.00       2/18          usart_receive_char [33]
                0.00    0.00       1/1           load_from_flash [35]
-----------------------------------------------
                0.00    0.00   30000/181242      tokenizer_init [11]
                0.01    0.00  151242/181242      tokenizer_next [5]
[2]    100.0    0.01    0.00  181242         get_next_token [2]
                0.00    0.00  130827/130827      singlechar [24]
-----------------------------------------------
                0.00    0.01   40202/40202       ubasic_run [4]
[3]    100.0    0.00    0.01   40202         line_statement [3]
                0.00    0.01   40202/40202       statement [6]
                0.00    0.00   40202/121110      accept [7]
                0.00    0.00   40202/50411       tokenizer_num [25]
-----------------------------------------------
                0.00    0.01   40202/40202       main [1]
[4]    100.0    0.00    0.01   40202         ubasic_run [4]
                0.00    0.01   40202/40202       line_statement [3]
                0.00    0.00   40202/231645      tokenizer_finished [23]
-----------------------------------------------
                0.00    0.00      31/151242      jump_linenum [18]
                0.00    0.00     101/151242      for_statement [19]
                0.00    0.00   10000/151242      gosub_statement [9]
                0.00    0.00   20000/151242      print_statement [8]
                0.00    0.01  121110/151242      accept [7]
[5]     83.4    0.00    0.01  151242         tokenizer_next [5]
                0.01    0.00  151242/181242      get_next_token [2]
                0.00    0.00  151242/231645      tokenizer_finished [23]
-----------------------------------------------
                0.00    0.01   40202/40202       line_statement [3]
[6]     77.8    0.00    0.01   40202         statement [6]
                0.00    0.00   10000/10000       print_statement [8]
                0.00    0.00   10000/10000       gosub_statement [9]
                0.00    0.00   10100/10100       next_statement [10]
                0.00    0.00   10000/10000       return_statement [16]
                0.00    0.00     101/101         for_statement [19]
                0.00    0.00       1/1           end_statement [21]
                0.00    0.00   40202/392176      tokenizer_token [22]
-----------------------------------------------
                0.00    0.00       1/121110      end_statement [21]
                0.00    0.00     202/121110      factor [14]
                0.00    0.00     404/121110      for_statement [19]
                0.00    0.00   10000/121110      print_statement [8]
                0.00    0.00   10000/121110      return_statement [16]
                0.00    0.00   20000/121110      varfactor [17]
                0.00    0.00   20000/121110      gosub_statement [9]
                0.00    0.00   20301/121110      next_statement [10]
                0.00    0.00   40202/121110      line_statement [3]
[7]     66.8    0.00    0.01  121110         accept [7]
                0.00    0.01  121110/151242      tokenizer_next [5]
                0.00    0.00  121110/392176      tokenizer_token [22]
-----------------------------------------------
                0.00    0.00   10000/10000       statement [6]
[8]     27.6    0.00    0.00   10000         print_statement [8]
                0.00    0.00   20000/151242      tokenizer_next [5]
                0.00    0.00   20000/20202       expr [13]
                0.00    0.00   10000/121110      accept [7]
                0.00    0.00  150000/392176      tokenizer_token [22]
-----------------------------------------------
                0.00    0.00   10000/10000       statement [6]
[9]     22.1    0.00    0.00   10000         gosub_statement [9]
                0.00    0.00   20000/121110      accept [7]
                0.00    0.00   10000/10000       jump_linenum [18]
                0.00    0.00   10000/151242      tokenizer_next [5]
                0.00    0.00   20000/392176      tokenizer_token [22]
                0.00    0.00   10000/50411       tokenizer_num [25]
                0.00    0.00   10000/10102       get_prog_text_pointer 
[32]
-----------------------------------------------
                0.00    0.00   10100/10100       statement [6]
[10]    16.7    0.00    0.00   10100         next_statement [10]
                0.00    0.00   20301/121110      accept [7]
                0.00    0.00    9999/29998 
jump_to_prog_text_pointer [12]
                0.00    0.00   20301/40301       ubasic_get_variable 
[26]
                0.00    0.00   10100/30201       tokenizer_variable_num 
[30]
                0.00    0.00   10100/10201       ubasic_set_variable 
[31]
-----------------------------------------------
                0.00    0.00       1/30000       ubasic_init [20]
                0.00    0.00       1/30000       jump_linenum [18]
                0.00    0.00   29998/30000 
jump_to_prog_text_pointer [12]
[11]    16.6    0.00    0.00   30000         tokenizer_init [11]
                0.00    0.00   30000/181242      get_next_token [2]
-----------------------------------------------
                0.00    0.00    9999/29998       jump_linenum [18]
                0.00    0.00    9999/29998       next_statement [10]
                0.00    0.00   10000/29998       return_statement [16]
[12]    16.6    0.00    0.00   29998         jump_to_prog_text_pointer 
[12]
                0.00    0.00   29998/30000       tokenizer_init [11]
-----------------------------------------------
                0.00    0.00     202/20202       for_statement [19]
                0.00    0.00   20000/20202       print_statement [8]
[13]    11.1    0.00    0.00   20202         expr [13]
                0.00    0.00   20202/20202       term [15]
                0.00    0.00   20202/392176      tokenizer_token [22]
-----------------------------------------------
                0.00    0.00   20202/20202       term [15]
[14]    11.1    0.00    0.00   20202         factor [14]
                0.00    0.00   20000/20000       varfactor [17]
                0.00    0.00     202/121110      accept [7]
                0.00    0.00   20202/392176      tokenizer_token [22]
                0.00    0.00     202/50411       tokenizer_num [25]
-----------------------------------------------
                0.00    0.00   20202/20202       expr [13]
[15]    11.1    0.00    0.00   20202         term [15]
                0.00    0.00   20202/20202       factor [14]
                0.00    0.00   20202/392176      tokenizer_token [22]
-----------------------------------------------
                0.00    0.00   10000/10000       statement [6]
[16]    11.0    0.00    0.00   10000         return_statement [16]
                0.00    0.00   10000/29998 
jump_to_prog_text_pointer [12]
                0.00    0.00   10000/121110      accept [7]
-----------------------------------------------
                0.00    0.00   20000/20000       factor [14]
[17]    11.0    0.00    0.00   20000         varfactor [17]
                0.00    0.00   20000/121110      accept [7]
                0.00    0.00   20000/30201       tokenizer_variable_num 
[30]
                0.00    0.00   20000/40301       ubasic_get_variable 
[26]
-----------------------------------------------
                0.00    0.00   10000/10000       gosub_statement [9]
[18]     5.5    0.00    0.00   10000         jump_linenum [18]
                0.00    0.00    9999/29998 
jump_to_prog_text_pointer [12]
                0.00    0.00      31/151242      tokenizer_next [5]
                0.00    0.00       1/30000       tokenizer_init [11]
                0.00    0.00      56/392176      tokenizer_token [22]
                0.00    0.00       7/50411       tokenizer_num [25]
                0.00    0.00       1/10102       get_prog_text_pointer 
[32]
-----------------------------------------------
                0.00    0.00     101/101         statement [6]
[19]     0.4    0.00    0.00     101         for_statement [19]
                0.00    0.00     404/121110      accept [7]
                0.00    0.00     202/20202       expr [13]
                0.00    0.00     101/151242      tokenizer_next [5]
                0.00    0.00     202/392176      tokenizer_token [22]
                0.00    0.00     101/30201       tokenizer_variable_num 
[30]
                0.00    0.00     101/10201       ubasic_set_variable 
[31]
                0.00    0.00     101/10102       get_prog_text_pointer 
[32]
-----------------------------------------------
                0.00    0.00       1/1           main [1]
[20]     0.0    0.00    0.00       1         ubasic_init [20]
                0.00    0.00       1/30000       tokenizer_init [11]
-----------------------------------------------
                0.00    0.00       1/1           statement [6]
[21]     0.0    0.00    0.00       1         end_statement [21]
                0.00    0.00       1/121110      accept [7]
-----------------------------------------------
                0.00    0.00      56/392176      jump_linenum [18]
                0.00    0.00     202/392176      for_statement [19]
                0.00    0.00   20000/392176      gosub_statement [9]
                0.00    0.00   20202/392176      factor [14]
                0.00    0.00   20202/392176      term [15]
                0.00    0.00   20202/392176      expr [13]
                0.00    0.00   40202/392176      statement [6]
                0.00    0.00  121110/392176      accept [7]
                0.00    0.00  150000/392176      print_statement [8]
[22]     0.0    0.00    0.00  392176         tokenizer_token [22]
-----------------------------------------------
                0.00    0.00   40201/231645      ubasic_finished [28]
                0.00    0.00   40202/231645      ubasic_run [4]
                0.00    0.00  151242/231645      tokenizer_next [5]
[23]     0.0    0.00    0.00  231645         tokenizer_finished [23]
-----------------------------------------------
                0.00    0.00  130827/130827      get_next_token [2]
[24]     0.0    0.00    0.00  130827         singlechar [24]
-----------------------------------------------
                0.00    0.00       7/50411       jump_linenum [18]
                0.00    0.00     202/50411       factor [14]
                0.00    0.00   10000/50411       gosub_statement [9]
                0.00    0.00   40202/50411       line_statement [3]
[25]     0.0    0.00    0.00   50411         tokenizer_num [25]
-----------------------------------------------
                0.00    0.00   20000/40301       varfactor [17]
                0.00    0.00   20301/40301       next_statement [10]
[26]     0.0    0.00    0.00   40301         ubasic_get_variable [26]
-----------------------------------------------
                0.00    0.00   40202/40202       usart_is_receive [29]
[27]     0.0    0.00    0.00   40202         Check_for_data [27]
-----------------------------------------------
                0.00    0.00   40202/40202       main [1]
[28]     0.0    0.00    0.00   40202         ubasic_finished [28]
                0.00    0.00   40201/231645      tokenizer_finished [23]
-----------------------------------------------
                0.00    0.00   40202/40202       main [1]
[29]     0.0    0.00    0.00   40202         usart_is_receive [29]
                0.00    0.00   40202/40202       Check_for_data [27]
-----------------------------------------------
                0.00    0.00     101/30201       for_statement [19]
                0.00    0.00   10100/30201       next_statement [10]
                0.00    0.00   20000/30201       varfactor [17]
[30]     0.0    0.00    0.00   30201         tokenizer_variable_num [30]
-----------------------------------------------
                0.00    0.00     101/10201       for_statement [19]
                0.00    0.00   10100/10201       next_statement [10]
[31]     0.0    0.00    0.00   10201         ubasic_set_variable [31]
-----------------------------------------------
                0.00    0.00       1/10102       jump_linenum [18]
                0.00    0.00     101/10102       for_statement [19]
                0.00    0.00   10000/10102       gosub_statement [9]
[32]     0.0    0.00    0.00   10102         get_prog_text_pointer [32]
-----------------------------------------------
                0.00    0.00       2/18          main [1]
                0.00    0.00      16/18          usart_read_line [34]
[33]     0.0    0.00    0.00      18         usart_receive_char [33]
-----------------------------------------------
                0.00    0.00       3/3           main [1]
[34]     0.0    0.00    0.00       3         usart_read_line [34]
                0.00    0.00      16/18          usart_receive_char [33]
-----------------------------------------------
                0.00    0.00       1/1           main [1]
[35]     0.0    0.00    0.00       1         load_from_flash [35]
-----------------------------------------------

 This table describes the call tree of the program, and was sorted by
 the total amount of time spent in each function and its children.

 Each entry in this table consists of several lines.  The line with the
 index number at the left hand margin lists the current function.
 The lines above it list the functions that called this function,
 and the lines below it list the functions this one called.
 This line lists:
     index  A unique number given to each element of the table.
    Index numbers are sorted numerically.
    The index number is printed next to every function name so
    it is easier to look up where the function in the table.

     % time  This is the percentage of the `total' time that was spent
    in this function and its children.  Note that due to
    different viewpoints, functions excluded by options, etc,
    these numbers will NOT add up to 100%.

     self  This is the total amount of time spent in this function.

     children  This is the total amount of time propagated into this
    function by its children.

     called  This is the number of times the function was called.
    If the function called itself recursively, the number
    only includes non-recursive calls, and is followed by
    a `+' and the number of recursive calls.

     name  The name of the current function.  The index number is
    printed after it.  If the function is a member of a
    cycle, the cycle number is printed between the
    function's name and the index number.


 For the function's parents, the fields have the following meanings:

     self  This is the amount of time that was propagated directly
    from the function into this parent.

     children  This is the amount of time that was propagated from
    the function's children into this parent.

     called  This is the number of times this parent called the
    function `/' the total number of times the function
    was called.  Recursive calls to the function are not
    included in the number after the `/'.

     name  This is the name of the parent.  The parent's index
    number is printed after it.  If the parent is a
    member of a cycle, the cycle number is printed between
    the name and the index number.

 If the parents of the function cannot be determined, the word
 `<spontaneous>' is printed in the `name' field, and all the other
 fields are blank.

 For the function's children, the fields have the following meanings:

     self  This is the amount of time that was propagated directly
    from the child into the function.

     children  This is the amount of time that was propagated from the
    child's children to the function.

     called  This is the number of times the function called
    this child `/' the total number of times the child
    was called.  Recursive calls by the child are not
    listed in the number after the `/'.

     name  This is the name of the child.  The child's index
    number is printed after it.  If the child is a
    member of a cycle, the cycle number is printed
    between the name and the index number.

 If there are any cycles (circles) in the call graph, there is an
 entry for the cycle-as-a-whole.  This entry shows who called the
 cycle (as parents) and the members of the cycle (as children.)
 The `+' recursive calls entry shows the number of function calls that
 were internal to the cycle, and the calls entry for each member shows,
 for that member, how many times it was called from other members of
 the cycle.



Index by function name

  [27] Check_for_data         [35] load_from_flash        [30] 
tokenizer_variable_num
   [7] accept                 [10] next_statement (ubasic.c) [28] 
ubasic_finished
  [21] end_statement (ubasic.c) [8] print_statement (ubasic.c) [26] 
ubasic_get_variable
  [13] expr                   [16] return_statement (ubasic.c) [20] 
ubasic_init
  [14] factor (ubasic.c)      [24] singlechar (tokenizer.c) [4] 
ubasic_run
  [19] for_statement (ubasic.c) [6] statement (ubasic.c)  [31] 
ubasic_set_variable
   [2] get_next_token (tokenizer.c) [15] term (ubasic.c)  [29] 
usart_is_receive
  [32] get_prog_text_pointer  [23] tokenizer_finished     [34] 
usart_read_line
   [9] gosub_statement (ubasic.c) [11] tokenizer_init     [33] 
usart_receive_char
  [18] jump_linenum (ubasic.c) [5] tokenizer_next         [17] varfactor 
(ubasic.c)
  [12] jump_to_prog_text_pointer [25] tokenizer_num
   [3] line_statement (ubasic.c) [22] tokenizer_token

ups.. sorry fuer das lange posting..
aber warum tokenizer_next bei dem print 150000 aufgeruffen wird .. ist 
mir nicht ganz klar...

lg roman( der mit der zahl :)

von TheMason (Gast)


Lesenswert?

@roman

Mal ne Frage zum Profiler. Welchen verwendest du, und wie funktioniert 
das. Gibt es das Tool kostenlos (wahrscheinlich nicht, oder ?)

von Roman65536 (Gast)


Lesenswert?

@theMason

GNU 8D

gcc -p ... umklammert jede funktion so, das man anschliessend runtime 
verhalten analyzieren kann. Die statistiken werden in einem gmon.out 
file gespeichert fuer analyze.

mit "gprof" kommt die statistik wie oben als output, mit weitern 
optionen kann man noch vieles mehr :) so zum beispiel output generieren 
fuer "dot" der das auch noch grafisch anzeigt .



viel Spass beim profilieren 8D

roman

von TheMason (Gast)


Lesenswert?

@roman

Danke erstmal für den hinweis :-). Ich nutze zwar eher Microsaft oder 
WinAVR, aber werds mal im Hinterkopf behalten.

von Roman65536 (Gast)


Lesenswert?

Bei den seattle softboys sollte es eigentlich (vor allem fuer die 
win32/64 compiler) auch so was geben. den das runtime profiling hat 
praktisch jeder compiler. zynisch gesagt, vielleicht sollten die mehr 
davon gebrauch machen :) oder haben sie angst was dabei raus kommt ??
zb. fuer linux kernel gibt es sowas aehnliches.. beim solaris kann man 
ganz anderst loessen, dort kann man kernel und app gleichzeitig und ohne 
grosse compiler unterstuetzung loessen (dtrace), so was gibt es glaube 
ich auch fuer linux..

Das ganze ist jedoch sehr hilfreich bei performance problemen ...

lg roman

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

auf meiner bekannten Projektseite ist eine aktuelle Version mit 
folgenden Änderungen verfügbar:

* einige interne Variablen wurden auf sinnvollere Datentypen angepasst 
(Integer ist nicht immer das Allheilmittel...)

* die weiter oben erwähnte Geschichte mit dem sinnlosen Parsen von 
Basic-Quelltexten bei der Suche einer bestimmten Zeilennummer bzw. neuen 
Zeile wurde verbessert (in tokenizer.c: jump_to_next_linenum() plus 
darauf aufbauende diverse Änderungen im Rest der Module...)

Letzte Änderung hat einige Verbesserungen bei der 
Abarbeitungsgeschwindigkeit gebracht. In meiner AVR-Testumgebung (siehe 
Projektseite) verringerte sich z.B. die Laufzeit des Prog0 (siehe 
ubasic_tests.h) um ca. 4ms. Für das eine Gosub, bei dem die Änderung zum 
tragen kommt, schon ein enormer Unterschied (15ms --> 11ms).

Nebenbei (und für mich auch bedeutend) wurden auch ein paar Byte 
Programmspeicherplatz eingespart....

Grüße Uwe

PS.: bei der Sache mit den zwischengemerkten goto-Sprungzielen muss ich 
noch ein wenig überdenken, wie man das am sinnvollsten macht....

von Roman65536 (Gast)


Lesenswert?

@uwe

PS.: bei der Sache mit den zwischengemerkten goto-Sprungzielen muss ich
noch ein wenig überdenken, wie man das am sinnvollsten macht....

Warum ?? Dachte du machst da nichts.. in die richtung ??

lg roman

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

Roman65536 schrieb:
> PS.: bei der Sache mit den zwischengemerkten goto-Sprungzielen muss ich
> noch ein wenig überdenken, wie man das am sinnvollsten macht....
> Warum ?? Dachte du machst da nichts.. in die richtung ??
>
och, naja, sind ja derzeit nur Überlegungen, die zum Schluß geführt 
haben, dass die Sache vielleicht doch ganz interessant sein könnte, wenn 
es auf Laufzeiten ankommt... Und so aufwändig ist die Sache nun auch 
wieder nicht, wenn man so etwas ähnliches macht, wie du oben 
vorgeschlagen hast.

Auf jeden Fall werde ich die Sache aber abschaltbar machen.

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

zuletzt diskutierte Zeilennummern-Cache ist jetzt eingebaut, die 
entsprechende Version ist auf bekannter Webseite verfügbar.

Berauschend sind die Laufzeitverbesserungen nicht unbedingt, wobei das 
aber im Zusammenhang mit meine gestrigen Änderung zu sehen ist, die an 
der gleichen Stelle ansetzte.

10 for i = 1 to 100
20 print i
30 gosub 100
40 next i
50 print a
60 end
100 a=a+1
110 return

Laufzeiten (auf meiner Testumgebung...)
*ohne Cache: 383ms
*mit Cache: 371ms

Grüße Uwe

von Joerg W. (joergwolfram)


Lesenswert?

Wenn auch "ausser Konkurrenz": Ich habe das mal mit der aktuellen 
ChipBasic Version nachgestellt (allerdings 10000 Durchläufe) und komme 
bei abgeschalteter Videoausgabe (16,17 MHz effektiver Takt) auf 87ms. 
Allerdings halt in ASM und die internen Strukturen sind auf 
Geschwindigkeit optimiert.

Gruß Jörg

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Hallo Jörg,

> ...und komme
> bei abgeschalteter Videoausgabe (16,17 MHz effektiver Takt) auf 87ms.

:-), hätte ich jetzt auch nicht anders erwartet, da dein ChipBasic halt 
in ASM implementiert ist (Hut ab davor! Meine Kenntnisse/Nerven reichen 
leider dazu nicht mehr. Vor 20 Jahren sah es noch anders aus...).

Eine Frage zu deinem Test: hattest du das print in der Schleife drin 
gelassen und wenn ja, via serieller Schnittstelle?

Grüße Uwe

von Joerg W. (joergwolfram)


Lesenswert?

Nein, ich habe das auf den Bildschirm ausgegeben (der allerdings dabei 
auch scrollen muß), jeden Wert in eine neue Zeile. Seriell könnte ich 
auch probieren, mit der System-Schnittstelle (2400Bps) braucht 
allerdings die Ausgabe schon 417ms. Aber ich kann über den zweiten USART 
des Mega644P ausgeben. Welche USART-Geschwindigkeit benutzt Du?

Gruß Jörg

von Uwe B. (boerge) Benutzerseite


Lesenswert?

...derzeit 57600 Baud (8n1).

Grüße Uwe

PS.: einen grossen Vorteil hat mein Interpreter ;-) --> er ist, wenn man 
das ganze AVR-spezifische-Zeugs ausschaltet, portierbar. Die ersten 
Versuche/Anpassungen mit dem Original-Codes habe ich unter Linux gemacht 
bevor ich dann auf einen AVR gegangen bin...

von roman65536 (Gast)


Lesenswert?

@uwe,


die gemessenen werte scheinen mir doch zu hoch!! da scheint etwas nicht 
mit rechten dingen zu gehen...

Probiere es doch ohne den Print und mit -O3 und nicht mit -Os.
Wenn es um speed gehen soll dann sicherlich mit allen optimierungen und 
nicht der size.

lg roman

von Dagobert (Gast)


Lesenswert?

Da wir hier schon in der Leistungsschlacht sind. Hier ein die Daten vom 
BasicBeetle (www.DieProjektseite.de):
1
5 DIM I,A:TICKER=0
2
10 FOR I=1 TO 100
3
20 PRINT I
4
30 GOSUB 100
5
40 NEXT 
6
50 PRINT A
7
60 PRINT TICKER:END 
8
100 A=A+1
9
110 RETURN

Ergibt 210 mS bei einer Baudrate der Ausgabe von 19200.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

Dagobert schrieb:
> Da wir hier schon in der Leistungsschlacht sind. Hier ein die Daten vom
> BasicBeetle (www.DieProjektseite.de):
>
da es ja (leider) keinen Quellcode zum Beetle gibt, wenigstens eine 
Antwort auf die Frage: ASM oder C oder etwas ganz anderes?

Grüße Uwe

von Dagobert (Gast)


Lesenswert?

Der BasicBeetle ist komplett in Assembler geschrieben.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

... na dann ist er ja ganz schön langsam... ;-)

...Spaß beseite! Ich denke mal es geht hier nicht um eine 
Leistungsschlacht der verschiedenen Projekte, zumal jeder eine etwas 
andere Zielsetzung hat. Ich zumindestens bin mit meinen Ergebnis 
eigentlich ganz zufrieden.

Die Laufzeitmessung habe ich letztens auch nur reingebaut, um zu sehen, 
welche Tuningmaßnahmen sinnvoll sind und was sie bringen. Interessanter 
ist fast noch das Profiling, welches letztens Roman hier gepostet hatte. 
Da sieht man noch viel deutlicher, wo man bei Optimierungen ansetzen 
sollte.

(Wenn ich meinen Interpreter auf einer schnelleren Plattform laufen 
lassen würde, was ja bei mir geht, würde ich wahrscheinlich supertolle 
Laufzeiten haben. Aber wie gesagt, eigentlich nicht so bedeutsam!)

Grüße Uwe

von Dagobert (Gast)


Lesenswert?

Ja. Der BasicBeetle ist für größere Projekte vorgesehen. Dies zeigt sich 
schon im Befehlsumfang und im unterstützten RAM.

Für eine kleine Alarmanlage oder eine kleine Lichtsteuerung ist dieser 
'oversized'. Da wäre deiner oder der ChipBasic wohl besser geeignet. 
Aber beim Steuern einer kompletten Modellbahnanlage oder umfangreiche 
Mess- und Steuerungsaufgaben, da geratet ihr wohl an die Grenzen. Da 
wird der BB erst langsam Munter ;)

Und die Entwicklung bleibt ja nicht stehen. Es sind weitere Versionen 
geplant, welche z.B. Multiprozessorsteuerungen ermöglichen oder es 
ermöglichen, eigene Befehle zu erstellen um z.B. sehr zeitkritische 
Programmsegmente in eigenen Code einzubinden.

von Roman65536 (Gast)


Lesenswert?

Da mein Name irgendwo gefallen ist, moechte ich zu der ganzen 
Performance sache auch etwas sagen.

Man muss den Dunkle interpretter ansehen als ein general Purpose 
interpreter und wie es Dunkle selbst sagt, just for fun. oder besser 
gesagt "mal kucken ob es funktioniert?" und im diesem sinne hat es 
funktioniert. Das konzept des interpretters ist der klassische 
lexer/parser ansatz. Ich bin ehrlich gesagt nicht sicher ob der lexer 
und parser wirklich der beste ist. ich denke jeder flex/yacc wuerde 
wahrscheinlich schnelleren code generieren.

Wenn es wirklich um geschwindigkeit geht, musste man den ansatz von 
Mason verfolgen. Den lexer und parser umbauen. gemaess profiling ist der 
interpretter in der get_next_token(), das wird sich nach einem umbau 
nicht aendern, jedoch schneller machen kann man es auf jeden fall.
Aus meiner erfahrung, steckt man ein paar stunden in die sache rein, 
kann man gewaltige sachen aendern.
zb. schaut man sich nur die singlechar() routine an .. if else if else 
etc...
ist im programm ein "=" muss der lexer alle if durchlaufen bis er den 
"=" findet. muss das so sein ?? eingentlich nicht. ok speicher ist immer 
ein problem. spendet man jedoch eine 128byte grosse tabelle, kann man 
alle singlechar() abdecken mit einem read.

schaut man sich die keyword an ist es das selbe.. eine typische 
anweissung
10 a=10 wird bei dem lexer als letztes analyzier, dh. alle bedinungen 
mussen negativ sein, bis er dies als TOKENIZER_VARIABLE erkennt.
die Keywords table so wie sie jetzt ist, ist eine zeitverschwendung. 
einfach zu programmieren (ich wuerde es ja auch so machen) aber sehr 
langsam. wuerde man zb. die keyword laenge in die tabelle reinnehmen und 
mit dem vorgegeben keyword vergleichen, wuerde es schon schneller gehen 
oder ein einsprung fuer die anfangs buchstaben, so das zb. beim print 
man let,goto,gosub,for gar nicht erst vergleicht.


in diesem sinne ... cycle jagt eroeffnet :)

roman

von TheMason (Gast)


Lesenswert?

@Roman

Genau aus diesem Performance-"Flaschenhals", sprich das zuerst 
erfolgende erkennen der Tokens (was ja je nach token schon ewig viele 
Takte braucht, bei den ganzen strcmp's, und sonstigen Prüffunktionen und 
späterem Abarbeiten des erkannten Tokens, ist hier sehr schlecht für die 
Performance.
Bei dem Byte-Code Ansatz wird ja eben genau dieser Teil "vorgekaut" und 
einfach nur die tokenizer_xxx Funktionen nicht auf Strings, sondern auf 
den Byte-Code gehetzt. Ich habe zwar noch keine Laufzeitmessungen 
gemacht, aber es dürfte sehr viel schneller sein.
Den eigebauten "Compiler" kann man im Prinzip weglassen, es sei denn man 
möchte sich mit dem AVR eine Basic-Entwicklungsumgebung schaffen 
(Compilieren von Basic-Quellcode von der SD-Karte und Speichern des 
Kompilats auf SD-Karte/Flash/EEProm und Ausführen desselbigen).
Nimmt man nur den Byte-Code lässt sich der Interpreter sicherlich auch 
mit sehr wenig auffwand in Assembler schreiben, womit man dann den 
ultimativen Geschwindigkeits-Kick bekommt. Ok, es ginge noch ne Stufe 
darüber, indem man PC-Seitig aus dem Basic-Programm direkt ASM-Code für 
den AVR erzeugt, aber das wäre ja am Ansatz vorbei.
Ich denke das mein Ansatz da eine Grundlage für verbesserte Performance 
bietet, sofern man aus dem mittlerweile entstandenen 
ifdef/define-Spaghetti-Monster die Essenz bzw den Kern herausschnippelt.
Würde mich jedenfalls freuen wenn jemand an meinem Ansatz mitwerkelt, da 
ích momentan noch kein Projekt habe in dem ich Basic-Code (egal ob Text 
oder Byte-Code) ausführen muß. Aber kommt vllt ja noch :-)

von Roman65536 (Gast)


Lesenswert?

ja klar .. nur das eigentlich problem wird ueber umweg weg 
programmiert..
ich meine verstehe mich nicht falsch ist auch ein ansatz. driftet 
allerdings schon in richtung JIT compilation ab und geht weg von einem 
reinem interpreter ansatz.

das sind halt zwei verschiedene dinge. Ich verstehe dein ansatzt ist ja 
auch cool. jedoch Uwe verfollgt einen anderen ansatzt und warum nicht 
auch den verfolgen ?? Im schlimmsten falle lernen wir nur etwas davon :)

Bei deinem ansatz frage ich mich .. warum den nicht gleich byte code von 
java verwenden und auf der nanovm lauffen lassen ?? aka 
Beitrag "Java auf AVR"



lg roman

von TheMason (Gast)


Lesenswert?

War ja auch nicht bös gemeint. Ich denke halt das der reine 
Interpreter-Ansatz eben sehr zeitintensiv ist. Es kommt ja auch immer 
auf den Anwendungsfall ab. Wenn beispielsweise eine komplexe 
Zeitschaltuhr damit programmiert werden soll kommt es sicherlich nicht 
auf ms-genaues Timing an. Überhaupt sind zeitkritische(re) Sachen (egal 
ob Text oder Byte-Code) sicherlich nicht geeignet um sich mit einem 
Basic-Dialekt lösen zu lassen.

Ich werde sicherlich auch hier noch weiter mitlesen und das ein oder 
andere in meinem Ansatz übernehmen.

>Im schlimmsten falle lernen wir nur etwas davon :)

Meinte ich weiter oben ja auch :-)
Wollte auch nur nochmal was Werbung für meinen Ansatz machen :-)
Und hoffe das bei mir auch bald eine gewisse Beteiligung einsetzt.

von Roman65536 (Gast)


Lesenswert?

Hey mason,

nicht falsch verstehen.. ich denke... ganz persoenlich.. man koennte 
doch beide mergen... wir koennten doch den von uwe verbessern und neben 
bei wurde ja auch kompilation bei deinem verbessert werden..

von TheMason (Gast)


Lesenswert?

@roman

Ich wär der letzte der da Nein sagen würde. Das können wir gerne machen. 
Ich denke ja ebenfalls das 3 Leute mehr Ideen haben/Fehler entdecken als 
einer. Von daher, immer gerne.

von Roman65536 (Gast)


Lesenswert?

Also gleiches programm mit Mason's Jit machine..

dh.
10 for i = 1 to 100\n\
15 for n = 1 to 100\n\
20 gosub 100\n\
30 next n\n\
30 next i\n\
40 end\n\
100 print n,i \n\
105 return\n\


Ach ja.. ignoriert die Check_for_data.. ist meine routine fuer Linux.
aber warum so viel mal die tokenizer_variable_num() ??



 gprof main
Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  us/call  us/call  name
 33.33      0.01     0.01    40202     0.25     0.25  Check_for_data
 33.33      0.02     0.01    30207     0.33     0.33 
tokenizer_variable_num
 16.67      0.03     0.01   372019     0.01     0.01  tokenizer_token
 16.67      0.03     0.01   171292     0.03     0.03  tokenizer_next
  0.00      0.03     0.00   251695     0.00     0.00  tokenizer_finished
  0.00      0.03     0.00   171293     0.00     0.00  get_next_token
  0.00      0.03     0.00   171211     0.00     0.00 
get_next_token_from_memory
  0.00      0.03     0.00   121211     0.00     0.04  accept
  0.00      0.03     0.00    40202     0.00     0.44  execbasicfunc
  0.00      0.03     0.00    40202     0.00     0.50  line_statement
  0.00      0.03     0.00    40202     0.00     0.45  statement
  0.00      0.03     0.00    40202     0.00     0.00  ubasic_finished
  0.00      0.03     0.00    40202     0.00     0.50  ubasic_run
  0.00      0.03     0.00    40202     0.00     0.25  usart_is_receive
  0.00      0.03     0.00    40200     0.00     0.00 
ubasic_get_variable
  0.00      0.03     0.00    29999     0.00     0.03  jump_linenum
  0.00      0.03     0.00    29999     0.00     0.03 
tokenizer_jump_to_pos
  0.00      0.03     0.00    20202     0.00     0.41  expr
  0.00      0.03     0.00    20202     0.00     0.38  factor
  0.00      0.03     0.00    20202     0.00     0.40  term
  0.00      0.03     0.00    20000     0.00     0.37  varfactor
  0.00      0.03     0.00    10201     0.00     0.00 
ubasic_set_variable
  0.00      0.03     0.00    10100     0.00     0.45  next_statement
  0.00      0.03     0.00    10000     0.00     0.11  gosub_statement
  0.00      0.03     0.00    10000     0.00     1.12  print_statement
  0.00      0.03     0.00    10000     0.00     0.07  return_statement
  0.00      0.03     0.00      229     0.00     0.00  tokenizer_num
  0.00      0.03     0.00      101     0.00     1.37  for_statement
  0.00      0.03     0.00       82     0.00     0.00 
get_next_token_from_text
  0.00      0.03     0.00       73     0.00     0.00 
drop_translated_token
  0.00      0.03     0.00       73     0.00     0.00 
tokenizer_drop_byte
  0.00      0.03     0.00       56     0.00     0.00  singlechar
  0.00      0.03     0.00       40     0.00     0.00 
tokenizer_get_token_size
  0.00      0.03     0.00       28     0.00     0.00  usart_receive_char
  0.00      0.03     0.00       13     0.00     0.00 
tokenizer_drop_word
  0.00      0.03     0.00        4     0.00     0.00  usart_read_line
  0.00      0.03     0.00        1     0.00     0.04  end_statement
  0.00      0.03     0.00        1     0.00     0.00  load_from_flash
  0.00      0.03     0.00        1     0.00     0.00  set_token_pointer
  0.00      0.03     0.00        1     0.00     0.00  tokenizer_init
  0.00      0.03     0.00        1     0.00     4.38 
tokenizer_translate
  0.00      0.03     0.00        1     0.00     0.00  ubasic_init

 %         the percentage of the total running time of the
time       program used by this function.

cumulative a running sum of the number of seconds accounted
 seconds   for by this function and those listed above it.

 self      the number of seconds accounted for by this
seconds    function alone.  This is the major sort for this
           listing.

calls      the number of times this function was invoked, if
           this function is profiled, else blank.

 self      the average number of milliseconds spent in this
ms/call    function per call, if this function is profiled,
     else blank.

 total     the average number of milliseconds spent in this
ms/call    function and its descendents per call, if this
     function is profiled, else blank.

name       the name of the function.  This is the minor sort
           for this listing. The index shows the location of
     the function in the gprof listing. If the index is
     in parenthesis it shows where it would appear in
     the gprof listing if it were to be printed.


         Call graph (explanation follows)


granularity: each sample hit covers 4 byte(s) for 33.33% of 0.03 seconds

index % time    self  children    called     name
                                                 <spontaneous>
[1]    100.0    0.00    0.03                 main [1]
                0.00    0.02   40202/40202       ubasic_run [3]
                0.00    0.01   40202/40202       usart_is_receive [8]
                0.00    0.00       1/1           tokenizer_translate 
[23]
                0.00    0.00   40202/40202       ubasic_finished [28]
                0.00    0.00       4/4           usart_read_line [39]
                0.00    0.00       3/28          usart_receive_char [37]
                0.00    0.00       1/1           load_from_flash [40]
                0.00    0.00       1/1           ubasic_init [43]
-----------------------------------------------
                0.00    0.02   40202/40202       ubasic_run [3]
[2]     66.7    0.00    0.02   40202         line_statement [2]
                0.00    0.02   40202/40202       statement [4]
                0.00    0.00   40202/121211      accept [14]
-----------------------------------------------
                0.00    0.02   40202/40202       main [1]
[3]     66.7    0.00    0.02   40202         ubasic_run [3]
                0.00    0.02   40202/40202       line_statement [2]
                0.00    0.00   40202/251695      tokenizer_finished [25]
-----------------------------------------------
                0.00    0.02   40202/40202       line_statement [2]
[4]     60.9    0.00    0.02   40202         statement [4]
                0.00    0.02   40202/40202       execbasicfunc [5]
                0.00    0.00   40202/372019      tokenizer_token [15]
-----------------------------------------------
                0.00    0.02   40202/40202       statement [4]
[5]     59.1    0.00    0.02   40202         execbasicfunc [5]
                0.00    0.01   10000/10000       print_statement [6]
                0.00    0.00   10100/10100       next_statement [17]
                0.00    0.00   10000/10000       gosub_statement [18]
                0.00    0.00   10000/10000       return_statement [21]
                0.00    0.00     101/101         for_statement [22]
                0.00    0.00       1/1           end_statement [24]
-----------------------------------------------
                0.00    0.01   10000/10000       execbasicfunc [5]
[6]     37.5    0.00    0.01   10000         print_statement [6]
                0.00    0.01   20000/20202       expr [10]
                0.00    0.00  150000/372019      tokenizer_token [15]
                0.00    0.00   20000/171292      tokenizer_next [16]
                0.00    0.00   10000/121211      accept [14]
-----------------------------------------------
                0.01    0.00   40202/40202       usart_is_receive [8]
[7]     33.3    0.01    0.00   40202         Check_for_data [7]
-----------------------------------------------
                0.00    0.01   40202/40202       main [1]
[8]     33.3    0.00    0.01   40202         usart_is_receive [8]
                0.01    0.00   40202/40202       Check_for_data [7]
-----------------------------------------------
                0.00    0.00       6/30207       tokenizer_translate 
[23]
                0.00    0.00     101/30207       for_statement [22]
                0.00    0.00   10100/30207       next_statement [17]
                0.01    0.00   20000/30207       varfactor [13]
[9]     33.3    0.01    0.00   30207         tokenizer_variable_num [9]
-----------------------------------------------
                0.00    0.00     202/20202       for_statement [22]
                0.00    0.01   20000/20202       print_statement [6]
[10]    27.7    0.00    0.01   20202         expr [10]
                0.00    0.01   20202/20202       term [11]
                0.00    0.00   20202/372019      tokenizer_token [15]
-----------------------------------------------
                0.00    0.01   20202/20202       expr [10]
[11]    26.8    0.00    0.01   20202         term [11]
                0.00    0.01   20202/20202       factor [12]
                0.00    0.00   20202/372019      tokenizer_token [15]
-----------------------------------------------
                0.00    0.01   20202/20202       term [11]
[12]    25.8    0.00    0.01   20202         factor [12]
                0.00    0.01   20000/20000       varfactor [13]
                0.00    0.00   20202/372019      tokenizer_token [15]
                0.00    0.00     202/121211      accept [14]
                0.00    0.00     202/229         tokenizer_num [31]
-----------------------------------------------
                0.00    0.01   20000/20000       factor [12]
[13]    24.9    0.00    0.01   20000         varfactor [13]
                0.01    0.00   20000/30207       tokenizer_variable_num 
[9]
                0.00    0.00   20000/121211      accept [14]
                0.00    0.00   20000/40200       ubasic_get_variable 
[29]
-----------------------------------------------
                0.00    0.00       1/121211      end_statement [24]
                0.00    0.00     202/121211      factor [12]
                0.00    0.00     505/121211      for_statement [22]
                0.00    0.00   10000/121211      print_statement [6]
                0.00    0.00   10000/121211      return_statement [21]
                0.00    0.00   20000/121211      varfactor [13]
                0.00    0.00   20000/121211      gosub_statement [18]
                0.00    0.00   20301/121211      next_statement [17]
                0.00    0.00   40202/121211      line_statement [2]
[14]    17.2    0.00    0.01  121211         accept [14]
                0.00    0.00  121211/171292      tokenizer_next [16]
                0.00    0.00  121211/372019      tokenizer_token [15]
-----------------------------------------------
                0.00    0.00   20202/372019      factor [12]
                0.00    0.00   20202/372019      term [11]
                0.00    0.00   20202/372019      expr [10]
                0.00    0.00   40202/372019      statement [4]
                0.00    0.00  121211/372019      accept [14]
                0.00    0.00  150000/372019      print_statement [6]
[15]    16.7    0.01    0.00  372019         tokenizer_token [15]
-----------------------------------------------
                0.00    0.00      82/171292      tokenizer_translate 
[23]
                0.00    0.00   20000/171292      print_statement [6]
                0.00    0.00   29999/171292      tokenizer_jump_to_pos 
[20]
                0.00    0.00  121211/171292      accept [14]
[16]    16.7    0.01    0.00  171292         tokenizer_next [16]
                0.00    0.00  171292/251695      tokenizer_finished [25]
                0.00    0.00  171290/171293      get_next_token [26]
-----------------------------------------------
                0.00    0.00   10100/10100       execbasicfunc [5]
[17]    15.0    0.00    0.00   10100         next_statement [17]
                0.00    0.00   10100/30207       tokenizer_variable_num 
[9]
                0.00    0.00   20301/121211      accept [14]
                0.00    0.00    9999/29999       jump_linenum [19]
                0.00    0.00   20200/40200       ubasic_get_variable 
[29]
                0.00    0.00   10100/10201       ubasic_set_variable 
[30]
-----------------------------------------------
                0.00    0.00   10000/10000       execbasicfunc [5]
[18]     3.8    0.00    0.00   10000         gosub_statement [18]
                0.00    0.00   20000/121211      accept [14]
                0.00    0.00   10000/29999       jump_linenum [19]
-----------------------------------------------
                0.00    0.00    9999/29999       next_statement [17]
                0.00    0.00   10000/29999       gosub_statement [18]
                0.00    0.00   10000/29999       return_statement [21]
[19]     2.9    0.00    0.00   29999         jump_linenum [19]
                0.00    0.00   29999/29999       tokenizer_jump_to_pos 
[20]
-----------------------------------------------
                0.00    0.00   29999/29999       jump_linenum [19]
[20]     2.9    0.00    0.00   29999         tokenizer_jump_to_pos [20]
                0.00    0.00   29999/171292      tokenizer_next [16]
-----------------------------------------------
                0.00    0.00   10000/10000       execbasicfunc [5]
[21]     2.4    0.00    0.00   10000         return_statement [21]
                0.00    0.00   10000/121211      accept [14]
                0.00    0.00   10000/29999       jump_linenum [19]
-----------------------------------------------
                0.00    0.00     101/101         execbasicfunc [5]
[22]     0.5    0.00    0.00     101         for_statement [22]
                0.00    0.00     202/20202       expr [10]
                0.00    0.00     101/30207       tokenizer_variable_num 
[9]
                0.00    0.00     505/121211      accept [14]
                0.00    0.00     101/10201       ubasic_set_variable 
[30]
-----------------------------------------------
                0.00    0.00       1/1           main [1]
[23]     0.0    0.00    0.00       1         tokenizer_translate [23]
                0.00    0.00      82/171292      tokenizer_next [16]
                0.00    0.00       6/30207       tokenizer_variable_num 
[9]
                0.00    0.00      47/73          tokenizer_drop_byte 
[34]
                0.00    0.00      40/40 
tokenizer_get_token_size [36]
                0.00    0.00      27/229         tokenizer_num [31]
                0.00    0.00      13/13          tokenizer_drop_word 
[38]
                0.00    0.00       2/171293      get_next_token [26]
-----------------------------------------------
                0.00    0.00       1/1           execbasicfunc [5]
[24]     0.0    0.00    0.00       1         end_statement [24]
                0.00    0.00       1/121211      accept [14]
-----------------------------------------------
                0.00    0.00   40201/251695      ubasic_finished [28]
                0.00    0.00   40202/251695      ubasic_run [3]
                0.00    0.00  171292/251695      tokenizer_next [16]
[25]     0.0    0.00    0.00  251695         tokenizer_finished [25]
-----------------------------------------------
                0.00    0.00       1/171293      tokenizer_init [42]
                0.00    0.00       2/171293      tokenizer_translate 
[23]
                0.00    0.00  171290/171293      tokenizer_next [16]
[26]     0.0    0.00    0.00  171293         get_next_token [26]
                0.00    0.00  171211/171211 
get_next_token_from_memory [27]
                0.00    0.00      82/82 
get_next_token_from_text [32]
-----------------------------------------------
                0.00    0.00  171211/171211      get_next_token [26]
[27]     0.0    0.00    0.00  171211         get_next_token_from_memory 
[27]
-----------------------------------------------
                0.00    0.00   40202/40202       main [1]
[28]     0.0    0.00    0.00   40202         ubasic_finished [28]
                0.00    0.00   40201/251695      tokenizer_finished [25]
-----------------------------------------------
                0.00    0.00   20000/40200       varfactor [13]
                0.00    0.00   20200/40200       next_statement [17]
[29]     0.0    0.00    0.00   40200         ubasic_get_variable [29]
-----------------------------------------------
                0.00    0.00     101/10201       for_statement [22]
                0.00    0.00   10100/10201       next_statement [17]
[30]     0.0    0.00    0.00   10201         ubasic_set_variable [30]
-----------------------------------------------
                0.00    0.00      27/229         tokenizer_translate 
[23]
                0.00    0.00     202/229         factor [12]
[31]     0.0    0.00    0.00     229         tokenizer_num [31]
-----------------------------------------------
                0.00    0.00      82/82          get_next_token [26]
[32]     0.0    0.00    0.00      82         get_next_token_from_text 
[32]
                0.00    0.00      56/56          singlechar [35]
-----------------------------------------------
                0.00    0.00      73/73          tokenizer_drop_byte 
[34]
[33]     0.0    0.00    0.00      73         drop_translated_token [33]
-----------------------------------------------
                0.00    0.00      26/73          tokenizer_drop_word 
[38]
                0.00    0.00      47/73          tokenizer_translate 
[23]
[34]     0.0    0.00    0.00      73         tokenizer_drop_byte [34]
                0.00    0.00      73/73          drop_translated_token 
[33]
-----------------------------------------------
                0.00    0.00      56/56 
get_next_token_from_text [32]
[35]     0.0    0.00    0.00      56         singlechar [35]
-----------------------------------------------
                0.00    0.00      40/40          tokenizer_translate 
[23]
[36]     0.0    0.00    0.00      40         tokenizer_get_token_size 
[36]
-----------------------------------------------
                0.00    0.00       3/28          main [1]
                0.00    0.00      25/28          usart_read_line [39]
[37]     0.0    0.00    0.00      28         usart_receive_char [37]
-----------------------------------------------
                0.00    0.00      13/13          tokenizer_translate 
[23]
[38]     0.0    0.00    0.00      13         tokenizer_drop_word [38]
                0.00    0.00      26/73          tokenizer_drop_byte 
[34]
-----------------------------------------------
                0.00    0.00       4/4           main [1]
[39]     0.0    0.00    0.00       4         usart_read_line [39]
                0.00    0.00      25/28          usart_receive_char [37]
-----------------------------------------------
                0.00    0.00       1/1           main [1]
[40]     0.0    0.00    0.00       1         load_from_flash [40]
-----------------------------------------------
                0.00    0.00       1/1           tokenizer_init [42]
[41]     0.0    0.00    0.00       1         set_token_pointer [41]
-----------------------------------------------
                0.00    0.00       1/1           ubasic_init [43]
[42]     0.0    0.00    0.00       1         tokenizer_init [42]
                0.00    0.00       1/1           set_token_pointer [41]
                0.00    0.00       1/171293      get_next_token [26]
-----------------------------------------------
                0.00    0.00       1/1           main [1]
[43]     0.0    0.00    0.00       1         ubasic_init [43]
                0.00    0.00       1/1           tokenizer_init [42]
-----------------------------------------------

 This table describes the call tree of the program, and was sorted by
 the total amount of time spent in each function and its children.

 Each entry in this table consists of several lines.  The line with the
 index number at the left hand margin lists the current function.
 The lines above it list the functions that called this function,
 and the lines below it list the functions this one called.
 This line lists:
     index  A unique number given to each element of the table.
    Index numbers are sorted numerically.
    The index number is printed next to every function name so
    it is easier to look up where the function in the table.

     % time  This is the percentage of the `total' time that was spent
    in this function and its children.  Note that due to
    different viewpoints, functions excluded by options, etc,
    these numbers will NOT add up to 100%.

     self  This is the total amount of time spent in this function.

     children  This is the total amount of time propagated into this
    function by its children.

     called  This is the number of times the function was called.
    If the function called itself recursively, the number
    only includes non-recursive calls, and is followed by
    a `+' and the number of recursive calls.

     name  The name of the current function.  The index number is
    printed after it.  If the function is a member of a
    cycle, the cycle number is printed between the
    function's name and the index number.


 For the function's parents, the fields have the following meanings:

     self  This is the amount of time that was propagated directly
    from the function into this parent.

     children  This is the amount of time that was propagated from
    the function's children into this parent.

     called  This is the number of times this parent called the
    function `/' the total number of times the function
    was called.  Recursive calls to the function are not
    included in the number after the `/'.

     name  This is the name of the parent.  The parent's index
    number is printed after it.  If the parent is a
    member of a cycle, the cycle number is printed between
    the name and the index number.

 If the parents of the function cannot be determined, the word
 `<spontaneous>' is printed in the `name' field, and all the other
 fields are blank.

 For the function's children, the fields have the following meanings:

     self  This is the amount of time that was propagated directly
    from the child into the function.

     children  This is the amount of time that was propagated from the
    child's children to the function.

     called  This is the number of times the function called
    this child `/' the total number of times the child
    was called.  Recursive calls by the child are not
    listed in the number after the `/'.

     name  This is the name of the child.  The child's index
    number is printed after it.  If the child is a
    member of a cycle, the cycle number is printed
    between the name and the index number.

 If there are any cycles (circles) in the call graph, there is an
 entry for the cycle-as-a-whole.  This entry shows who called the
 cycle (as parents) and the members of the cycle (as children.)
 The `+' recursive calls entry shows the number of function calls that
 were internal to the cycle, and the calls entry for each member shows,
 for that member, how many times it was called from other members of
 the cycle.



Index by function name

   [7] Check_for_data         [40] load_from_flash        [16] 
tokenizer_next
  [14] accept                 [17] next_statement         [31] 
tokenizer_num
  [33] drop_translated_token   [6] print_statement        [15] 
tokenizer_token
  [24] end_statement          [21] return_statement       [23] 
tokenizer_translate
   [5] execbasicfunc          [41] set_token_pointer       [9] 
tokenizer_variable_num
  [10] expr                   [35] singlechar             [28] 
ubasic_finished
  [12] factor                  [4] statement              [29] 
ubasic_get_variable
  [22] for_statement          [11] term                   [43] 
ubasic_init
  [26] get_next_token         [34] tokenizer_drop_byte     [3] 
ubasic_run
  [27] get_next_token_from_memory [38] tokenizer_drop_word [30] 
ubasic_set_variable
  [32] get_next_token_from_text [25] tokenizer_finished    [8] 
usart_is_receive
  [18] gosub_statement        [36] tokenizer_get_token_size [39] 
usart_read_line
  [19] jump_linenum           [42] tokenizer_init         [37] 
usart_receive_char
   [2] line_statement         [20] tokenizer_jump_to_pos  [13] varfactor
romanp@dhcp-ezrh04-51-123:~/Desktop/ubasic-0.2a$



lg roman

von Roman65536 (Gast)


Lesenswert?

man koennte doch die .. tokenizer_variable_num als makro einbinden..
den.. fuer die paar instruktionen lohnt sich doch ein jsr gar nicht...

lg roman

von Roman65536 (Gast)


Angehängte Dateien:

Lesenswert?

@an alle basic fans..

im anhang findet ihr ueberarbeitete version von dem tokenizer..

was ist anderst.. die structure keyword enthaelt nun keyword laenge..

struct keyword_token {
#if USE_PROGMEM
  // um via strxxx_P zugreifen zu koennen, muss eine feste Laenge 
vorgegeben
  // werden
  char keyword[MAX_KEYWORD_LEN+1];
#else
  char *keyword;
#endif
  char len;
  int token;
};


dem entsprechend muss man die keyword ergaenzen :
  {"let",3, TOKENIZER_LET},

nun.. die routine mystrlen() gibt die laenge an von dem ptr string, dh. 
wie lange ist der naechst isaplha() string. wenn diese kleiner als 2 
ist, kann man die keywords ueberspringen, den die sind alle 2+ .
sollte der string 2+ sein, geht man nicht keyword per keyword, sondern 
vergleicht zu erst die laenge der strings (was fuer eine bloede 
bezeichnung :) erst wenn diese gleich ist, werden die keywords zeichen 
per zeichen verglichen.

als naechstes gehe die singlechar() an :)

lg roman

von Roman65536 (Gast)


Angehängte Dateien:

Lesenswert?

so jetzt mit dem FAST singlechar()... auch noch..
beim compilieren -DFAST angeben..

bei den ersten test's sollten wir naeher den 80ms kommen :)


lg roman

von TheMason (Gast)


Lesenswert?

@roman

Hört sich mal sinnig an, selbst wenns sich im ersten Moment etwas 
Konfizius liest :)
Aber gute lösung mit dem keyword Vergleich und der Single-Char 
Optimierung.
Gefällt mir gut. Werde ich wohl bei mir so übernehmen.
Evtl. kann ich auch noch was zur "Abstraktion" der "Zeichenquelle" 
beitragen. Habe bei mir mal eine generische Funktion (bzw 4 generische 
Funkionen) eingebaut mit denen der Text von einer beliebigen Quelle 
kommen kann. Dazu braucht man 4 Funktionen : Aktuelles Zeichen, Nächstes 
Zeichen, Zeichenposition holen, Zeichenposition setzen.
Mit den 4 Funktionen lässt sich der tokenizer von überall aus füttern 
:-)
Der Quellcode folgt noch.

von Roman65536 (Gast)


Lesenswert?

@mason,

hmmm... finde ich gut, aber man muss bedenken, so lange das ganz im 
arbeitspeicher vorhanden ist, kann man was schnell tun. abstrahiert man 
dies. muss man fuer alles wieder eine routine aufruffen, kann mir nicht 
vorstellen das dies schnell sein kann. ausser man tut dies ala getdent 
von linux. man gibt dem system call entsprechenden speicher und der 
kernel fuellt dies bis zum rand. single char finde ich nicht sooo gut.

Ehrlich gesagt verstehe ich auch nicht ganz die abstraktion .. warum den 
??
das man es von quelle a oder quelle b lesen kann ?? so von eeprom oder 
sd karte ?? geht es um das ??

lg roman

PS: danke fuer den lob, was das deutsch angeht .. na ja .. nicht meine 
staerke :) da waere schwizerduetsch scho besser.. hihihi..

von Rene B. (themason) Benutzerseite


Lesenswert?

@Roman

>so lange das ganz im arbeitspeicher vorhanden ist, kann man was schnell tun

Das ist richtig, aber der Hauptspeicher (SRAM) ist ja nunmal sehr 
begrenzt.

>kann mir nicht vorstellen das dies schnell sein kann

Schneller wirds dadurch leider nicht, aber ich denke je nach Größe des 
Basic-Programms kommt man schneller an die Grenzen des SRAMs als einem 
lieb ist.

>Ehrlich gesagt verstehe ich auch nicht ganz die abstraktion .. warum den??
>das man es von quelle a oder quelle b lesen kann ?? so von eeprom oder
>sd karte ?? geht es um das ??

Genau darum geht es. Das man beispielsweise ein Basic-Programm "direkt" 
d.h. über den Sektor-Puffer, den man ohnehin benötigt, ausführt. Wenn 
ein Basic-Programm beispielsweise 1kByte hat (1kByte ASCII bekommt man 
ja recht schnell zusammen) dann würde es schon nicht mehr in einen 
ATMega16 reinpassen. Man kann zwar mit Tricks und Kniffen vllt den 
"erweiterten" Speicher durch umkopieren "simulieren", aber selbst dazu 
muß man an der Stelle ansetzen an der es um die zeichenweise 
Verarbeitung geht (wenn man beispielsweise auf einer 512-Byte Grenze ist 
und den nächsten Sektor, die nächste Page oder wie auch immer holen muß) 
und dort dann umkopiert.
Mit den Funktionszeigern dauert es zwar länger, aber dafür lässt sich 
dann die "befütterung" auf nur jede erdenkliche Art lösen, bzw es kann 
jedes Medium (egal ob SD-Karte/HDD/ext. SRAM/EEProm/Flash/DataFlash oder 
sonstwas) an den Basic-Interpreter angekorkt werden. Außerdem lässt sich 
die Quelle während des Betriebs umschalten. Somit könnte man 
beispielsweise Basic-Programme "nachladen" bzw als getrennte Einheit vom 
Programmfluß ausführen und nachher wieder an der alten Stelle 
zurrückkehren.

von Roman65536 (Gast)


Lesenswert?

@Mason,

hast du dir schon mal die stdio von Unix/linux angeschaut ??
hier eine idee dazu.. blockweise wuerde es gehen.. man liest die 512 von 
der sd oder von wo auch immer. der rest passiert in einem buffer per 
macros.
wo bei ich ein grosses problem bei einem reinem interpretter sehe (bei 
deiner version auch) was mach tun mit den spruengen ?? da kann man den 
ptr nicht mehr speichern so wie es Uwe tut.

@ alle

koennte jemand irgend ein basic programm probieren was die aenderungen 
ueberhaupt bringen ?? mit allen speed optionen ?? ich kommen an avr 
heute nicht ran, muss noch was erledigen. wuerde mich aber 
interessieren..

lg
roman

von Rene B. (themason) Benutzerseite


Lesenswert?

>wo bei ich ein grosses problem bei einem reinem interpretter sehe (bei
>deiner version auch) was mach tun mit den spruengen ?? da kann man den
>ptr nicht mehr speichern so wie es Uwe tut.

Genau dafür brauche ich GETPOS und SETPOS. Damit lässt sich innerhalb 
meines Streams (Programm) der Zeiger setzen und lesen wie ich will. Der 
Zeigertyp ist per define definierbar. Damit ist es egal ob man sich 
beispielsweise mit einem Index auf ein Array bezieht, einen Zeiger 
innerhalb des SRAMs, einen virtuellen 32-Bit Zeiger auf einen 
Speicherbereich in einem externen großen RAM, einen 32-Bit Zeiger 
innerhalb der SD-Karte, einen 16-Bit Index bezogen auf den Anfang einer 
Text-Datei auf der SD-Karte.
Mit dieser Abstraktion (4 separate Funktionen plus einen "Zeigertyp") 
lässt sich die Quelle für das Basic-Programm an nahezu jedwede Umgebung 
anpassen.
Das ganze ist auch für die Simulation sehr nützlich.
Man ist damit wirklich sehr flexibel. Allerdings nimmt man dadurch auch 
Laufzeit einbußen in Kauf. Aber ich denke in Anbetracht der 
Möglichkeiten (und der ansonst vorhandenen begrenzung des 
Basic-Programms auf den Bruchteil des SRAMs) die sich ergeben kann man 
(bzw ich) das verschmerzen.
Auch wenn es um den Byte-Code geht lässt sich diese Abstraktion (fast) 
direkt umsetzen bzw direkt verwenden, dadurch das der Tokenizer 
transparent umschaltbar ist und von der Quelle der Daten nichts weiß bis 
auf eben die 4 Funktionen die der Tokenizer nutzt.

von Roman65536 (Gast)


Lesenswert?

@mason,


hmmm... irgendwie macht es schon sinn. mal schauen was der uwe sagt 
dazu.
Aber eine anmerkung, kannst du compiler/interpreter umbauen, das die 
sachen von oben mit singlechar und keyword einfliessen ?? wuerde mich 
wundernehmen was die aenderungen bringen.

ich denke zu erst sollte man das ding as fast as possible umbauen, ab 
dann ist es nicht mehr schwer den rest einbauen. Was man auf alle faelle 
vermeiden sollte, etwas "jetzt" einbauen und spaeter merken dass man 
sich dadurch performance eingebust hat.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Roman65536 schrieb:
> mal schauen was der uwe sagt dazu.

derzeit nicht viel, weil ich mich derzeit auf dem Sprung in den Urlaub 
bin und dazu noch ein paar Dinge erledigen muss...

Die Geschichte mit dem wahlfreien Medium geistert derzeit auch in meinem 
Kopf rum, wobei meine Gedanken in die Richtung gehen:
* eine ganze Textzeile einlesen und parsen, oder
* immer soviel lesen, wie das längste Schlüsselwort sein kann usw.

Set- und Getpos ist schon klar und war auch mein erster Gedanke, aber 
irgendwie muss ja mit den Schlüsselwörtern in Gänze verglichen werden...

Grüße Uwe

von Rene B. (themason) Benutzerseite


Lesenswert?

@Roman

Ich glaube da ist ein kleiner gedanklicher Fehler in deinem Source.
Und zwar holst du mit mystrlen via isaplha die Länge des zu suchenenden 
Schlüsselwortes. Das Problem ist nur wenn du auf z.b. >=, >> <> usw 
stößt, da isalpha hier nicht funktioniert und die Längen-Prüfung des 
Schlüsselwortes fehlschlägt. Mit isalpha lassen sich wirklich nur Wörter 
eingrenzen. Bei Symbolen wie <, >, = usw müsste man singlechar aufbohren 
das diese Fkt einem die 2-Zeichen Tokens zurückliefert. Aber damit wär 
es eben kein singlechar mehr ;-)

@Uwe

>* eine ganze Textzeile einlesen und parsen, oder
>* immer soviel lesen, wie das längste Schlüsselwort sein kann usw.

Ich denke das man mit Funktionszeiger für einzelne Zeichen inkl 
Get/SetPos schon sehr weit kommt. Zumal man beim 
zeilenweisen/blockweisen Verarbeiten ohnehin eine gesonderte Lesefkt 
benötigt die zu gegebener Zeit (sprich beim lesen des CRs) angestoßen 
werden muß.
Die Sache mit dem Vergleichen der Schlüsselwörter in ihrer Gänze wäre 
evtl noch die Möglichkeit eine weiter Funktion des "Zeichengerätes" zu 
implementieren. Egal ob diese im ersten Schritt nur zeichenweise 
vergleicht, oder aber über soviel eigenen Buffer verfügt diesen 
Vergleich im lokalen SRAM vollführen zu können (bei zeilenweiser 
Verarbeitung z.b.).
Also das die Implementierung letztendendes Sache des Mediums ist.

Aber so gesehen hätte man ja auch noch per Compilerschalter die 
Möglichkeit bestimmte Optimierungen zu setzen

Erstmal schönen Urlaub Uwe

von Roman65536 (Gast)


Lesenswert?

Kann sein.. ich dachte isaplha kommt mit den sonderzeichen klar :(
na ja .. wieder an die taste :)


uwe schoenen urlaub 8-D

lg roman

von TheMason (Gast)


Lesenswert?

Dann mach ich mal das 100. Posting voll :-)

@roman

Ist auch nur ne Vermutung das isaplha damit nicht zurechtkommt. War auch 
nur ein Bauchgefühl das beispielsweise ? oder ! keine Buchstaben sind 
:))

Kannst du mir mal deine EMail zukommen lassen ?

@roman und uwe

Also ich denke vllt sollten wir wirklich mal zu dritt an dem Basic 
arbeiten. Man kann ja eine Gemeinschaftsversion machen, und jeder für 
sich seine bevorzugte Version. Jedenfalls wäre ich dafür wenn wir ein 
SVN-Repository beantragen in dem die einzelnen Erkenntnisse und Ideen 
zusammenfließen. Vllt wäre ja noch ein Unterordner für jede 
"persönliche" Basic Version sinnig.

Was haltet ihr von der Idee ?

von Roman65536 (Gast)


Lesenswert?

@mason,


isalpha gilt nur fuer buchstaben, keine sonderzeichen. koennte evtl. 
sein das deine avr-libc ein bug hat ?? oder generell ein problem hat ??

Diese sollte nur bei buchstaben zurueck geben.

lg roman

von TheMason (Gast)


Lesenswert?

@roman

>War auch nur ein Bauchgefühl das beispielsweise ? oder ! keine Buchstaben >sind 
:))

Das war nur ein Scherz :-)
isalpha darf eben nur bei Buchstaben true zurückliefern.
Desalb hab ich ja auch den vermeintlichen Fehler in deine Source 
gefunden.
Aber ich denke das man trotzdem deinen Ansatz mit der vorgeschalteten 
Längenprüfung gut verwenden kann, da es den Vergleich deutlich 
beschleunigt.

von Roman65536 (Gast)


Lesenswert?

meine email hast in deine uc mailbox :)

ich haette da noch eine perversere idee .. jedoch .. sollte mal wissen 
ob es den bis jetzt was gebracht hat ??



lg roman

von TheMason (Gast)


Lesenswert?

Jo danke. Meld mich später mal per EMail.

>sollte mal wissen ob es den bis jetzt was gebracht hat ??

Ich denke es wäre sinnig mal mehrere kleine Basic-Programme zu schreiben 
mit denen man unterschiedliche Szenarien testen kann. Das man immer 
dieselben Bedingungen hat und somit von Version zu Version vergleichen 
kann. Dazu muß man sich dann aber auf den gemeinsamen Funktionsumfang 
beschränken. Sprich kein Call von Uwe und keine Extensions von mir.

Aber nochmal zu der SVN-Idee ... Wär das was ?

Was hast du denn noch für Schweinereien bezüglich des Basics im Kopf ?

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

TheMason schrieb:
> Aber nochmal zu der SVN-Idee ... Wär das was ?

von der Sache nicht schlecht, aber welche Version willst du als 
Ausgangspunkt nehmen?

Grüße Uwe

von TheMason (Gast)


Lesenswert?

@Uwe

Im Zweifelsfalle die Ursprungsversion von Adam :))

Was mir da vorschwebt wäre als erste Version ein Mix aus deiner und 
meiner Version.

Von dir die bisherigen Optimierungen und Fehlerkorrekturen. Von mir die 
Sache mit der einfachen Konfiguration per basic_cfg.h.

Die Präprozessor-Befehle brauchen ja keine Laufzeitressourcen bzw 
Vergrößern den Code ja nicht, sondern dienen lediglich der einfacheren 
Übersicht bzw Erweiterbarkeit.
Ich schnapp mir heute Abend mal deinen Code und modifiziere diesen, 
sodass der Code an sich derselbe bleibt, aber eben die Wartbarkeit was 
die Schlüsselworte angeht erhöht wird. Wär das ein Anfang für eine 
Version ?
Im anschluß würde ich dann meine Extensions und die Compiler-Fähigkeit 
hinzunehmen. Aber da kann man sich ja noch überlegen ob man das in 
getrennten Verzeichnissen weiterführt.

von Roman65536 (Gast)


Lesenswert?

@mason,


fiha, da will's eine wissen..

SVN na ja .. aber wo ?? hast du gleich einen server ?? oder gibt es hier 
einen ??


Was mich zu erst interessieren wuerde, was den die einzelnen 
verbesserungen ueber bringen ??  an einfachen programmen.. bevor man was 
ueberhaupt tut.
resp. den code aufraeumt. eine erweiterung resp. wenn man die laenge des 
keyword schon weiss, warum dann nicht "nur" die keywort tabelle 
durchsuchen, mit der entsprechenden laenge der keyworter ??

how about it ??

von NurEinGast (Gast)


Lesenswert?

Roman65536 schrieb:
> SVN na ja .. aber wo ?? hast du gleich einen server ?? oder gibt es hier
> einen ??

http://www.mikrocontroller.net/articles/Hilfe:SVN

von TheMason (Gast)


Lesenswert?

>Was mich zu erst interessieren wuerde, was den die einzelnen
>verbesserungen ueber bringen ??

Aber dazu muss man ja immer diesselben Test-Bedingungen haben. Sprich 
gleiche Plattform (sollte ja kein Thema sein) und gleiches 
Basic-Programm (ist ja auch kein Thema).
Ich denke das wenn man sich ein paar Test-Programme überlegt lassen sich 
auch die Versionen untereinander immer gleich vergleichen. Also das man 
immer gleiche Bedingungen hat.

Ich werd den Andreas mal fragen ob er uns ein SVN-Repository einrichtet.

von Roman65536 (Gast)


Lesenswert?

Also... so wie es aussieht.. bringen die verbesserungen mit der keyword 
laenge extrem viel...

getestet wuerde dieses kleine programm:

const char prog1[] PROGMEM=
"\
5 for x = 1 to 100\n\
10 for i = 1 to 100\n\
15 for n = 1 to 100\n\
20 gosub 100\n\
30 next n\n\
30 next i\n\
35 next x\n\
40 end\n\
100 print n,i \n\
105 return\n\
";

dh. 100*100*100 den print raus zu geben.. oder 10'000'000 mal.
Das ganze wuerde auf Linux probiert..

hier die resultate :

 time ./main <cmd.txt  >/dev/null

real  0m1.764s
user  0m1.764s
sys  0m0.000s


time ./main <cmd.txt  >/dev/null

real  0m4.686s
user  0m4.652s
sys  0m0.004s

Die erste version ist mit den verbesserungen im bereich von single char 
und keyword laenge vergleich..

die zweite original ..
Ich denke die laufzeiten sprechen fuer sich :D


lg roman

von Rene B. (themason) Benutzerseite


Lesenswert?

@Roman

Also die Optimierung ist doch mal ne Erwähnung Wert :-))
Ich werd das mal übernehmen und in mein unverständliches Kauderwelsch an 
Präprozessor-Anweisungen mit integrieren :))

Was mir zum Thema Speed-Optimierung noch eingefallen ist. Für die 
Schlüsselwortsuche würde sich auch der Hash-Algorithmus (in Verbindung 
mit der Länge des Keywords) anbieten.
Ich stelle mir das so vor :
Sobald ein Token mit einem Buchstaben anfängt wird die Hash von diesem 
und allen folgenden Alpha-Zeichen gebildet. Gleichzeitig werden die 
Anzahl der Buchstaben mitgezählt.
In einer Tabelle stehen dann die Hashwerte mit den entsprechenden Längen 
und den zu repräsentierenden Token-Nummern.
Und gesucht wird mit n/2. Also sprich die Hash-Tabelle ist aufsteigend 
sortiert. Man fängt in der Mitte an und schaut ob der Wert größer oder 
kleiner ist (oder gleich). Ist er kleiner mache ich dasselbe Spiel vom 
Tabellenanfang bis zur Mitte (also mitte des Bereichs bestimmen, 
nachgucken ob größer, kleiner). Ist er größer so betrachte ich von der 
Tabellenmitte an bis Tabellenende.
Ob das ganze schneller wird müsste man Testen.
Ich werd auch mal mit dem AVR-Simulator Test-Programme durchrödeln und 
schauen was dabei rauskommt.

von Roman65536 (Gast)


Lesenswert?

Rene !!
You got a mail..


hash halte ich in diesem speziellen fall als ungeeignet. den...
Stellt dir vor.. ich erweitere "mein" interpreter mit neuen cmd.
und dann stimmt der hash nicht mehr.. was dann ??

siehe email.. die idee ist vieeeeelllll besser :)

lg roman

von Rene B. (themason) Benutzerseite


Lesenswert?

@Roman

hab dir gerade "kurz" geantwortet :-)
Die Idee mit der Hash-Table denke ich ist auch nicht so gut bzw dürfte 
nicht soviel bringen. Aber ich hab noch 2-3 andere Ideen. Eine davon 
wäre eine Ergänzung zu deiner Längen-Tabellen-Idee.

von Roman65536 (Gast)


Lesenswert?

so weiter resultate Renes(mason) version ohne und mit compiler...

gleiches programm wie oben:


time ./main <cmd.txt  >/dev/null

real  0m27.257s
user  0m27.110s
sys  0m0.000s

VORSICHT dies ist noch nicht compilierte code..

und jetzt ... Meine damen und Herren, der Hammer !!

time ./main <cmd.txt  >/dev/null

real  0m0.775s
user  0m0.772s
sys  0m0.000s

Mein Respekt !!!
das ist 35 mal schneller als original !! oder
2.27 mal schneller als die oben erwaehnte beste resultat.

von Roman65536 (Gast)


Lesenswert?

Hier noch schnell ein vergleich mit C compilierte version ...

#include <stdio.h>


main()
{

short a,b,c;

for(a=0;a<100;a++)
 for(b=0;b<100;b++)
  for(c=0;c<100;c++)
  printf("%d %d\n",b,c);

}

 gcc -O6 -o test test.c

 time ./test >/dev/null

real  0m0.262s
user  0m0.236s
sys  0m0.000s

fyi.

von Rene B. (themason) Benutzerseite


Lesenswert?

@Roman

Erstmal Danke für deine unermüdliche Profiling-Arbeit :-))
Das das so viel schneller ist hätte ich nicht gedacht. Aber freut mich 
und bestärkt mich darin weiter mit dem "parallel" Ansatz (sprich Basic 
Quell-Code zu interpretieren, bzw vorinterpretierten Code ausführen) zu 
machen, bzw weitere Schweinereien in dem Basic-Interpreter 
unterzubringen.

von Roman65536 (Gast)


Lesenswert?

@rene

das ist doch noch kein profiling die execution zeit zu messen ;)

Du solltest dir mal Linux entwicklungs moeglichkeiten anschauen ...
auch wenn nur in der virtualBox oder so was.

lg roman

von Rene B. (themason) Benutzerseite


Lesenswert?

@roman

Bin leider mehrmals gescheitert effektiv mit Linux zu arbeiten. Drum 
bleib ich bei Windoof.
Aber hast schon recht. Ne Zeitmessung ist noch kein richtiges Profiling. 
Selbst wenn man mal auf die schnelle schauen kann ob Optimierungen den 
erhofften erfolg bringen.

von Roman65536 (Gast)


Lesenswert?

So lieber Rene...


ich nehmen mal dein code unter mein performance adler auge...

ein beispiel .. relation()..

int relation(void)
{
  int r1, r2;
  char op;

  r1 = expr();
  op = tokenizer_token();
  ;
 while (
# 1 "basic_cfg.h" 1
# 104 "basic_cfg.h"
   (op == TOKENIZER_EQ) ||
  (op == TOKENIZER_GT) ||
  (op == TOKENIZER_LT) ||
  (op == TOKENIZER_NE) ||
  (op == TOKENIZER_GE) ||
  (op == TOKENIZER_LE) ||
# 333 "ubasic.c" 2
  (0)) {
    tokenizer_next();
    r2 = expr();
    ;
  switch (op)
  {
# 1 "basic_cfg.h" 1
# 104 "basic_cfg.h"
  case TOKENIZER_EQ : r1 = basic_rel_eq (r1, r2); break;
  case TOKENIZER_GT : r1 = basic_rel_gt (r1, r2); break;
  case TOKENIZER_LT : r1 = basic_rel_lt (r1, r2); break;
  case TOKENIZER_NE : r1 = basic_rel_ne (r1, r2); break;
  case TOKENIZER_GE : r1 = basic_rel_ge (r1, r2); break;
  case TOKENIZER_LE : r1 = basic_rel_le (r1, r2); break;
# 346 "ubasic.c" 2
 }
    op = tokenizer_token();
  }
  return r1;
}

hier der compiler generierte code mit avr-gcc -O3 ..  dh. funktionen 
werden auch inlined..

.global  relation
  .type  relation, @function
relation:
  push r14
  push r15
  push r17
  push r28
  push r29
/* prologue: function */
/* frame size = 0 */
  rcall expr
  mov r28,r24
  mov r29,r25
  rcall tokenizer_token
  mov r17,r24
  rjmp .L208
.L227:
  cpi r17,lo8(22)
  breq .L217
  cpi r17,lo8(23)
  breq .L218
  cpi r17,lo8(24)
  brne .L226
  rcall tokenizer_next
  rcall expr
  ldi r18,lo8(0)
  ldi r19,hi8(0)
  cp r24,r28
  cpc r25,r29
  brlt .L215
.L225:
  ldi r18,lo8(1)
  ldi r19,hi8(1)
.L215:
  mov r28,r18
  mov r29,r19
  rcall tokenizer_token
  mov r17,r24
.L208:
  mov r24,r17
  subi r24,lo8(-(-36))
  cpi r24,lo8(3)
  brsh .L227
  rcall tokenizer_next
  rcall expr
  cpi r17,lo8(37)
  breq .L210
  cpi r17,lo8(38)
  breq .L228
  ldi r18,lo8(0)
  ldi r19,hi8(0)
  cp r28,r24
  cpc r29,r25
  brge .L215
  rjmp .L225
.L217:
  rcall tokenizer_next
  rcall expr
  ldi r18,lo8(0)
  ldi r19,hi8(0)
  cp r28,r24
  cpc r29,r25
  brne .L225
  rjmp .L215
.L218:
  rcall tokenizer_next
  rcall expr
  ldi r18,lo8(0)
  ldi r19,hi8(0)
  cp r28,r24
  cpc r29,r25
  brlt .L215
  rjmp .L225
.L228:
  ldi r18,lo8(0)
  ldi r19,hi8(0)
  cp r28,r24
  cpc r29,r25
  brne .L215
  rjmp .L225
.L210:
  ldi r18,lo8(0)
  ldi r19,hi8(0)
  cp r24,r28
  cpc r25,r29
  brge .L215
  rjmp .L225
.L226:
  mov r14,r28
  mov r15,r29
  mov r24,r28
  mov r25,r15
/* epilogue start */
  pop r29
  pop r28
  pop r17
  pop r15
  pop r14
  ret
  .size  relation, .-relation


ziemlich viel code nur fuer ein einfaches while und case ??
ginge es den nicht besser ??
ich denke schon...


baut man das ganze einbisschen um.. geht es schneller...

das musste doch etwas bringen ?? als der case ...

int * func_t []=
  { 
basic_rel_eq,basic_rel_gt,basic_rel_lt,basic_rel_ne,basic_rel_ge,basic_r 
el_le};

/*---------------------------------------------------------------------- 
-----*/
int relation(void)
{
  int r1, r2;
  TOKEN op;
   unsigned char tmp;
  int ( * func)(int,int );

  r1 = expr();
  op = tokenizer_token();
  DEBUG_PRINTF("relation: token %d\n", op);
  func=func_t[tmp];
  if((op >= TOKENIZER_EQ) &&  (op <= TOKENIZER_LE))
 {
   tmp=op-TOKENIZER_EQ;

    tokenizer_next();
    r2 = expr();
    DEBUG_PRINTF("relation: %d %d %d\n", r1, op, r2);

    r1=(func)(r1,r2);


    op = tokenizer_token();
  }
  return r1;
}





 time ./main <cmd.txt >/dev/null

real  0m0.745s
user  0m0.736s
sys  0m0.000s

hmm.. nicht viel aber immer hin...
ich denke der expr() waere auch so ein kandidat :)

lg roman

von Roman65536 (Gast)


Lesenswert?

vergisst das zeug da oben...
funktioniert ohne grobe aenderungen am compiler nicht. tja ... sackgasse

von Rene B. (themason) Benutzerseite


Lesenswert?

Welches Zeug ?

von Roman65536 (Gast)


Lesenswert?

funktions call ueber pointer , resp. vermeidung von switch{}.
Wenn die TOKENs zu weit liegen (von den Nummerierung) generiert der 
compiler ein undurchsichtigen code von if_then_else_may. genau das selbe 
gilt auch fuer die while bedinung.

geht nicht.. da die TOKENIZER_ definition in einer bestimmten 
reihenfolge sein muesste. Wenn es der fall waere, koennte man es so tun.

von Rene B. (themason) Benutzerseite


Lesenswert?

Sry, aber ich versteh das Problem nicht ganz.
Funktionszeiger wären doch ideal. Gerade bei Tokens die weiter "hinten" 
stehen, also weiter hinten im switch-case müsste sich eine größere 
zeitersparnis geben.
Was du meinst mit den "zusammenhängenden Tokens" und korrespondierenden 
Funktionszeigern lässt sich ja ganz einfach dadurch machen indem man der 
Token-Struktur den Funktionszeiger hinzufügt. Dann ist es egal ob 
zusammenhängend oder nicht, der Zeiger wird immer mitgeführt und ist 
immer korrekt. So habe ich es ja in meiner Version (die in dem eigenen 
Thread, aber auch hier in dem Thread) gemacht.
Das alles passiert ja in der "execbasicfunc". Und die könnte man evtl. 
noch per Makro ersetzen um Zeit zu sparen. Die Checks die da gemacht 
werden sind wahrscheinlich eh überflüssig.

von Michael B. (michael123)


Lesenswert?

Hallo,

ich wühle jetzt mal diesen Thread wieder raus, denn genau sowas suche 
ich.

Soweit ich das bis jetzt gesehen habe, gibt es 3 Version, eigentlich ja 
4.
Einmal die Ur-Version, auf der alles aufbaut (Version 4 :-) )
Dann die von Uwe, von Roman und von Rene.

Alle drei Versionen haben ihr eigenheiten, die von Uwe ist auf Platz 
optimiert, die von Roman und Rene auf Geschwindigkeit. Wobei die von 
Roman auch auf Platz. Sehe ich das richtig?
Was den Funktionsumfang betrifft: Da werd ich noch nicht ganz schlau.

Was mich persöhnlich angeht: Ich suche etwas, bei dem ich die Programm 
von SD Karte einlesen kann. Ein Zusatzfunktion, die per USB die Daten 
auf die SD Karte vom PC ablegen kann.
Aber das könnte ich auch selber einbauen.

Speziell geht es mir darum, dass ich grundlegende Basic Funktionen habe 
und das ganze so schnell wie nur mögich abläuft (Also Renes Version)

Habe auch mal in den SVN Teil geschaut, da ist leider noch nichts drin. 
Schade.

Wäre schön, wenn es hier weiter geht.

Gruß
Michael

von Rene B. (themason) Benutzerseite


Lesenswert?

>Ich suche etwas, bei dem ich die Programm von SD Karte einlesen kann

Ich habe mal in der Zwischenzeit was gebastelt (aber noch nicht hier 
rein gestellt), mit dem sich meine Version mit beliebigen Quellen 
füttern lassen kann, da es nun nicht mehr zwingend notwendig ist den 
Quellcode komplett im RAM zu halten. Damit ließe sich sowohl der Text 
als auch die vorinterpretierten z.b. von einer SD Karte ohne großen 
Aufwand direkt ausführen lassen.
Im moment bin ich noch dabei die Version aufzuhübschen und zu testen. 
Werde aber die Tage (so ich dazu komme) diese Version in dem anderen 
Thread posten.


>Habe auch mal in den SVN Teil geschaut, da ist leider noch nichts drin.

Das SVN-Repository ist für Uwe angelegt worden. Nur er kann Leute 
hinzufügen die was einchecken können. Aber da er seine Version ja auf 
seiner Seite gehostet hat weiß ich nicht ob das für ihn zu attraktiv bzw 
nützlich ist alles über SVN zu machen.

>Wäre schön, wenn es hier weiter geht.

Das wird es sicherlich :-)

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

sitze gerade in einem Internetcafe ca. 10250km von Berlin entfernt, 
geniesse den letzen Tag Urlaub und werde morgen wieder in Dt. online 
sein... Deshalb keine besonderen Aktivitaeten in den letzten Wochen und 
auch noch nichts im SVN. Es geht aber bald weiter.

Renes Geschichte mit dem Einlesen des Programmtextes wuerde mich (dann) 
auch interessieren.

Also bis demnaechst,
Uwe

von Rene B. (themason) Benutzerseite


Lesenswert?

Dann genieß den letzten Tag Urlaub mal schön :-)

Freu mich schon darauf wenn es weitergeht. Habe meine Version schon 
aufgehübscht und noch etwas getestet (AVR und WIN32). Wird morgen oder 
übermorgen gepostet.

Bis die Tage dann.

PS. Freut mich das Interesse an der Zeichengeräte-Geschichte (so hab ich 
das Einlesen von untersch. Quellen genannt) besteht.

von Rene B. (themason) Benutzerseite


Lesenswert?

Um den 0x80sten Eintrag in diesem Thread zu posten, und um nochmal auf 
mein neuesten Ableger des AVR-uBasics auf Adam Dunkels basierend 
aufmerksam zu machen entführe ich diesen Thread noch einmal kurz. (Man 
möge mir verzeihen).
Features des Werkes bzw Verbrechens (je nach belieben) sind unter

Beitrag "Basic-Interpreter für AVR auf Basis von Adam Dunkels uBasic"

zu finden.

Viel Spaß damit.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

ich habe mal begonnen die Projektseite für den SVN-Einstieg zur 
avr-basic (http://www.mikrocontroller.net/articles/AVR_BASIC) 
aufzubauen. Der Upload der Quelltexte ins SVN erfolgt am Wochenende 
(wenn ich mich mal ein wenig mit Subversion vertraut gemacht habe; ich 
verwende privat CVS als Versionskontrollsystem...)

@René
Du kannst ja mal anfangen auch deine Version auf dieser Seite kurz zu 
beschreiben, die entsprechende Überschrift ist bereits enthalten....

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Nachtrag: die Quellen befinden sich jetzt im SVN: 
http://www.mikrocontroller.net/svnbrowser/avr-basic/

von Rene B. (themason) Benutzerseite


Lesenswert?

Habe auch die Quellen in SVN hinzugefügt sowie den Artikel 
vervollständigt.

von roman65536 (Gast)


Lesenswert?

habe irgendwo meinen namen gelesen...

Ich habe nur Spass an dem basic. eines Tages wenn ich mal gross bin (bin 
ja erst 41) werde ich was daraus tun. Meine Version (wenn man es so 
bezeichnen kann) ist, das möglichste aus dem code raus zu holen, speed 
und platz. Das sich der code zwischen durch verkleinert kommt ganz 
automatisch.
zb. die Anpassung mit der keyword laenge, bringt unglaublich viel 
performance so wie auch der Anpassung von single_char. Der Trick ist 
anschliessend den compilierten code anzuschauen. den.. schaut man sich 
nur die single_char routine an, es sind unglaublich viele if then else 
if .. das generiert einen viele jumps im code.. die modifizierte 
Version, man fuegt eine Tabelle mit den entsprechenden Informationen ein 
und der single_char ist nur noch ein lookup.

eine meine Ideen geht leider nur bei der Interpreter Version und nicht 
bei Rene's version. Rene arbeitet mit include's resp. durch geschickte 
Anordnung von defines, werden tabellen automatisch erstellt resp. code 
fuer den Compiler generiert durch den Preprocessor.

jedoch.. Routine wie relation() oder auch expr().. wird ja überprüft, ob 
es sich um die Vergleichs Operationen handelt resp. um die 
entsprechenden tokens. Was der compiler generiert ist ein unglaublich 
lange Spagetti code, bei dem jeder token einzeln verglichen wird. Durch 
geschickte Anlegens von den Tokens, dh. alle tokens die eine Routine 
braucht sind der reihe nach in der token Tabelle definiert, kann man die 
while( reduzieren auf ein (token > TOKEN_WAS && token < TOKEN_WAS2) 
spart viel Assembler Code!!!

Der switch konstrukt von GCC, produziert einen unglaublich viel code ... 
da alles überprüft wird und viel compares und jumps im code einbaut.
je nachdem.. muss die CPU alle diese Überprüfungen durchlaufen, bis die 
eigentlich Arbeit zb. nur eine Addition durchgeführt wird. muss das sein 
?? nein.. dies kann man vermeiden, durch geschickte "C" Programmierung..
neben Effekt.. man spart viel code, ein gesparte Code muss nicht von der 
CPU abgearbeitet werden :)

lg roman

von Roman65536 (Gast)


Lesenswert?

Frage an das Publikum....

Wer ist interessiert an frei waehlbaren variable name ??

ala ..

10 gugus=10
20 print gugus, gugus+10
run
10 20

resp. wo kann ich die aenderungen rein platzieren ??
lg roman

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Hallo Roman,

dir ist aber schon bewußt, dass das "Ur-Basic" auch keine Variablennamen 
mit mehr als einen Buchstaben zuläßt? Diese "Unsitte" ist erst später 
dazu gekommen....

Grüße Uwe

von Roman65536 (Gast)


Lesenswert?

ist jedoch sehr hilfreich ...
welche der ur-basics meinst du ??
der ms basic hat es schon immer gehabt zb. auch auf den cp/m maschinen.
dec basic, ncr basic und und und und... nur dir mini/micro basic hatten 
es nicht.

zu dem .. unter urbasic findet man auch bei der wikipedia nix ??
siehe http://de.wikipedia.org/wiki/Kategorie:Programmiersprache_Basic

ist eine lustige argumentation ... findest du nicht ??
sogar der 8052 build in interpretter hat es.

ich finde es macht schon sinn auch in kleinen apps. die uebersicht zu 
bewahren.
also..

10 alarm_status = 1

liesst sich nun mal besser als
10 a=1

oder
10 temperatur_error=temperatur_user - temperatur_current

auch ja noch eine sache.. man ist nicht mehr auf die 26 variablem 
begrenzt :)



lg roman

von Rene B. (themason) Benutzerseite


Lesenswert?

Die Idee die Variablenbegrenzung (zum einen nur 1 Buchstabe und zum 
zweiten, nur 26 davon) aufzuheben hab ich auch schon seit geraumer Zeit 
im Kopf.
Es stimmt schon das man den Programmfluss besser versteht wenn man 
sprechende Namen verwendet. Aber das Problem ist das die ordentlich RAM 
benötigen. Und bei meinetwegen 5-10 Namensbytes sind 2 Bytes für nen 
Integer dann ziemlicher overkill.

Was eine Möglichkeit wäre, wäre z.b. eine Hash-Tabelle anzulegen. Dann 
hätte man noch einen Kompromiss zw Namenslänge und Nutzdaten. Ist aber 
auch nicht ganz unkritisch.

Ich denke solange man kein wie auch immer angebundenes SRAM (es sei denn 
man erlabt sich an den 16KByte eines ATMega1284P ;-P, aber das ist ja 
nicht Sinn und Zweck der Sache) hat, sind lange Variablennamen (ab 3-4 
Zeichen) auf begrenztem SRAM nur mit Tricks oder Einschränkungen 
möglich.

von roman65536 (Gast)


Lesenswert?

eins verstehe ich dann doch nicht..
warum immer diese nur AVR begrenzung ??

ich verwende ja eine hash table mit pointer auf linked list.
die wiederum ist relativ klein. so sind die variablem schnell gefunden.

oder soll ich auch noch ein branch anfangen ??
bei der compiler version denke ich mir, koennte es viel einfacher sein.
den der muss nicht wirklich die namen speichern, sondern sich nur memory 
merken wo diese sind.

roman

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Roman65536 schrieb:
> welche der ur-basics meinst du ??

ich kann mich dunkel daran erinnern, dies im Buch "Visionäre der 
Programmierung: Die Sprachen und ihre Schöpfer" im Interwiew mit dem 
Basic-Vater gelesen zu haben....

Nebenbei, ein sehr lesenswertes Buch, wenn man sich für Sprachdesign, 
Softwareergonomie, Projektmanagment u.ä. beschäftigt. Da sind einige 
sehr interessante (teilweis kontroverse/streitbare) Äusserungen zu 
diesen Themen von den einzelnen Leuten abgedruckt.

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

roman65536 schrieb:
> warum immer diese nur AVR begrenzung ??

:-) naja, weil (zumindestens) mein Hintergedanke bei diesem Interpreter 
war, dass er auf einem AVR laufen soll. Klar, ohne diese Beschränkung 
könnte man der sehr viel machen und soll dich auch nicht hindern dies in 
einem eigenen Zweig zu tun!

Grüße Uwe

von chris (Gast)


Lesenswert?

Hallo Zusammen,

habt Ihr euch schon mal Gedanken gemacht, Timing-Funktionen einzuführen?

Für Schleifen mit definierter Laufzeit wäre so was sehr nützlich.

z.B. so:

10 print "hallo"
20 waitForNextMillisecond(1000)
30 goto 10

Die Funktion "waitForNextMillisecond" wartet dabei 1000 Millisekunden, 
aber bezogen auf den letzten Aufruf von "waitForNextMillisecond". Damit 
lässt sich eine definierte Schleifenlaufzeit erreichen. Diese Funktion 
gibt es z.B. in LabView und auch beim Propellerchip von Parallax ist 
dieser Mechanismus verfügbar.

von Rene B. (themason) Benutzerseite


Lesenswert?

@chris

Timerfunktionen lassen sich bei meiner Version einfach über die 
C-Erweiterungen einbauen, so ala (keine Gewähr) :

I16 vTimerWaitMs (T_USER_DATAS stDatas)
{
  delay_ms (stDatas [0].ulLong);
}

Für ein definiertes Zeitverhalten ist/sind wahrscheinlich noch einige 
Zusatz-Funktionen nötig die einen Zeitpunkt (Millisekunden) "festhalten" 
und beid der Warte-Funktion eben sich auf diesen Zeitpunkt beziehen.

Eine weitere Idee die mir im Kopf rumschwirrt ist ähnlich dem Microsoft 
Basic ein Konstrukt ähnlich dem "on timer x goto y". Weiterhin denkbar 
wäre z.b. ein "on error goto y" oder wenn man Fifos hat ein "on fifo x 
goto y" oder sowas. Solche Features dürften recht einfach zu realisieren 
sein. Evtl nehm ich das mit in die nächste Version als Option mit auf.

von chris (Gast)


Lesenswert?

Hallo Rene,

danke für Deine Antwort. Ich bin schon auf die nächste Version gespannt.
Gerade eben habe ich mir mal den Source heruntergeladen.
Mit den Copyrights im Programmkopf komme ich allerdings nicht ganz klar. 
Es gibt eine Version von Dir, in der nur Dein Name im Programmkopf steht 
und es gibt eine Version von Uwe Berger mit seinem Copyright. Die 
Grundidee stammt wohl von Adam Dunkel.
Sollte im Programmkopf nicht etwa die Liste der Autoren stehen?

Bester Gruß,
chris

von Joerg W. (joergwolfram)


Lesenswert?

Meiner Erfahrung nach ist ein "on timer x gosub y" besser als ein "on 
timer x goto y", in einer ähnlichen Form habe ich das auch bei meinem 
ChipBasic realisiert. Damit kann man dann periodisch anfallende Aufgaben 
sozusagen "im Hintergrund" laufen lassen. Bei einem Fehler ist GOTO wohl 
die bessere Lösung, allerdings sollte man einen Fehlercode und/oder die 
Zeile bei der der Fehler auftrat herausbekommen.

Jörg

von Rene B. (themason) Benutzerseite


Lesenswert?

@Chris

In den unter SVN eingecheckten Sourcen sind die Copyright-Abschnitte 
auch geradliniger. Bei der alten Version hatte ich noch Fehler in den 
Abschnitten gehabt.

@Jörg

Ich meinte auch ein Gosub, hatte aber Goto geschrieben.

von chris (Gast)


Lesenswert?

>Meiner Erfahrung nach ist ein "on timer x gosub y" besser als ein "on
>timer x goto y", in einer ähnlichen Form habe ich das auch bei meinem
>ChipBasic realisiert

Klingt wie ein Timer-Interrupt in C oder Assembler.
Das ist natürlich eine nützliche Sache. Ich persönlich würde ein 
Multitasking-Konzept vorziehen. Also einfach mehrere Basic-Programme 
gleichzeitig laufen lassen. Die Kommunikation der einzelnen Programme 
könnte man einfach über gleich Variablen mit gleichem Namen laufen 
lassen.

von Martin (Gast)


Lesenswert?

Gab es ähnlich schon 1986 (AH-8052 Basic von Intel).

von Martin (Gast)


Lesenswert?

... "on timer x gosub y" ...

Gab es ähnlich schon 1986 (AH-8052 Basic von Intel).

von chris (Gast)


Lesenswert?

Das Basic kann für Windows und AVR compiliert werden.
1
#ifdef AVR
2
#endif
3
4
#ifdef WIN32
5
#endif

In welchem File findet sich
1
#define AVR

Ich habe alle Files durchsucht, aber nichts gefunden?

von Joerg W. (joergwolfram)


Lesenswert?

@chris

das ist letztendlich auch eine Art "Timer-Interrupt". Im Timer-Interrupt 
wird periodisch ein Flag gesetzt. Vor jedem BASIC Befehl werden 
verschiedene Flags getestet (z.B. CTRL-C für Programmabbruch) und eben 
auch das Timer-Flag. Ist es gesetzt, wird es gleich wieder gelöscht und 
das GOSUB in den Programmablauf "hineingemogelt". Das spart Code, denn 
man kann die normalen GOSUB-Routinen (Stack-Handling) dafür verwenden.

Jörg

von chris (Gast)


Lesenswert?

Hallo Wolfram,

was ich schon immer mal sagen wollte: Deine Webseite 
http://www.jcwolfram.de/projekte/avr/chipbasic32/main.php finde ich 
richtig gut. Übersichtlich, klar strukturiert, kein SchnickSchnack.
Den BASIC Computer finde ich auch recht nett. Ich habe das Projekt schon 
am Anfang gesehen. Sehr minimalistisch, das maximale aus einem AVR 
herausgeholt, sehr schön.

Beste Grüße,
chris

von chris (Gast)


Lesenswert?

Hier meine erste Version des UBasic-AVR für das XPLAIN Board:

http://www.hobby-roboter.de/forum/viewtopic.php?f=4&t=123&p=519

von Rene B. (themason) Benutzerseite


Lesenswert?

@chris

#define AVR bzw #define WIN32 muß man nicht definieren. Diese defines 
sind Platformabhängig gesetzt, d.h. bei einem WIN32-C-Compiler ist immer 
WIN32 definiert. Bei einem AVR-GCC ist AVR immer definiert. Auf einem 
ARM dürfte (sollte) demnach immer ARM vorhanden sein, um auf die 
jeweiligen Unterschiede der Platform eingehen zu können.

@Jörg

>Vor jedem BASIC Befehl werden verschiedene Flags getestet

Ganz genau so wird das wohl auch implementiert werden. Allerdings mache 
ich mir gerade Gedanken dazu wie man das Flag-Handling und die 
korrespondierenden on XXX gosub y Befehle "parametrieren" kann.
Dadurch (soll) kann man dann ganz einfach ein "on timer x gosub y", "on 
flag xy gosub y", "on uart_receive gosub y", "on fifo x gosub y", usw 
selbst anlegen und das Basic um eigene "ON XXX GOSUB Y" erweitern. Mal 
schauen wie ich das am besten umsetze (da es ja auch von den Anwendern 
verstanden werden muß)

von chris (Gast)


Lesenswert?

>@chris
>#define AVR bzw #define WIN32 muß man nicht definieren.

OK, aber wie ist es, wenn ich mit dem GCC unter Linux kompilieren will?

BTW: Die Trennung zwischen den Plattformen über die defines kann ein 
wenig ausufern. Jetzt hätten wir schon die Plattformen Win,AVR und 
XPLAIN. Man könnte vielleicht noch einfach ARM-Boards dazunehmen.
Dein Kommandointerface ist ganz nützlich. Schade, dass kein einfacher 
Editor dabei ist, mit dem man ein Basic-Programm ins EEPROM hacken kann. 
Bei den früheren Computern wie z.B. ZX81 konnte man ein Programm 
schreiben, indem man am Anfang eines Befehls die Zeilennummer 
geschrieben hat. So eine einfach Eingabe wäre sehr nützlich.

von Rene B. (themason) Benutzerseite


Lesenswert?

@Chris

Mmh.. Is'n Argument.
Evtl gibt es noch Platform-defines ala X86 die man verwenden könnte.
Oder man geht den umgekehrten Weg und ersetzt WIN32 durch X86 (falls es 
bei allen Betriebssystemen und C-Compilern auf dem PC nicht ohnehin ein 
X86 define gibt)
In der platform.h (o.ä.) macht man dann folgendes

#ifdef WIN32
  #define X86
#endif
#ifdef LINUX_IRGENDWAS
  #define X86
#endif

Somit wäre dann für Windows und Linux gesorgt.

>Die Trennung zwischen den Plattformen über die defines kann ein
>wenig ausufern

Das sollte auch NUR bei den Teilen gemacht werden die wirklich nicht 
"emuliert" werden können bzw nicht auf gemeinsame Fkt zurückgeführt 
werden können.
Am sinnigsten wäre es alle Hardware-Funktionen so zu kapseln das sie auf 
jeder Platform benutzt werden können. So wirds in dem Demo ja auch 
gemacht, allerdings gibt es immer mal wieder Situationen in denen man 
direkt unterscheiden muß (bei Windows braucht man keine Initialisierung 
für printf, beim AVR und ARM schon ...)
Aber ich geb dir recht, es kann definitiv ausufern :-)

>Man könnte vielleicht noch einfach ARM-Boards dazunehmen.

Würd ich gerne machen, aber für ARM hab ich noch keine IDE und mit 
ARM-GCC und den Programmern steh ich ein wenig auf "Kriegsfuß" bzw hab 
noch keine "einfache" komplett IDE mit der man "mal eben" loslegen kann, 
ansonsten bin ich auf jedenfall dafür die ARM-Platformen mit 
aufzunehmen.

>Dein Kommandointerface ist ganz nützlich.

Danke :-) Hört man doch gerne.
Es gibt auch einen (bzw 2) Threads dazu. Der Kommandointerpreter ist ein 
eigener Zweig der mittlerweile doch schon sehr Leistungsfähig ist.
So können in meiner Entwicklungsversion auch Ausdrücke verwendet werden 
(also z.b. "test 1+2+3+4*(4+5+c_var), c_arr[c_var+3]"), die ebenfalls 
Funktionsaufrufe in C erlauben (ähnlich wie mit den Extensions in meiner 
Basic-Version). Es wird auch noch (sofern ich dazu komme) ein XML-Reader 
geben der sogar auf dem AVR lauffähig ist und einfach zu benutzen ist.

Ein Editor müsste in der Tat noch her. Allerdings wird es mit dem RAM 
denke ich sehr eng. Aber Möglichkeiten gibt es da bestimmt :-)

von chris (Gast)


Lesenswert?

Hallo Rene,

hier ein kleines Update:
http://www.hobby-roboter.de/forum/viewtopic.php?f=4&t=123

Ich habe angefangen, die Platformspezifischen Funktionen auszulagern.
Das Header-File für alle Plattformen lautet

platfom_specific.h

Für die einzelnen Plattformen müssen dann die spezifischen C-Files 
dazukompiliert werden:

für Windows: platform_specific_WIN32.c
für das XPLAIN-Board: platform_specific_XPLAIN.c

Was mir aufgefallen ist: Mit der AVR-printf-Funktion scheint es ein 
Problem zu geben. Das System stürzt bisweilen ab. Das hatte ich bei 
früheren Programmen schon mal, wenn ich printf verwendet habe. Es 
scheint wohl irgendwelchen Speichermüll zu produzieren. Ich bin deshalb 
bei meinen anderen Programmen dazu übergegangen, kein printf zu 
verwenden und statt dessen alle print Funktionen selbst zu definieren 
und nur das eigene serielle putchar zu verwenden.

BTW: hier ist der Thread zum XPLAIN-Board
Beitrag "XMEGA/ AVR-EXPLAIN code examples und Diskussion"

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

habe gerade eine neue Version des "Uwe-Berger-Zweiges" ins SVN gestellt. 
Folgende (interne) Änderungen:

-ein kleiner Codereview
-endlich mal wieder für Nicht-AVR-Plattformen übersetzbar gemacht
-nextptr eleminiert (als Vorbereitung für andere Ideen)
-Speicherplatz- und Performance-Optimierungen
-Syntax-Änderung bei Befehlen DIR, IN, OUT, da so logischer
-Doku entsprechend angepasst

Grüße Uwe

von Rene B. (themason) Benutzerseite


Lesenswert?

@chris

Hatte eig gedacht das ich auf dein Posting geantwortet hätte, aber habs 
wohl verbaselt abzuschicken ...

Also die platformspezifischen Unterschiede auf mehrere Dateien 
aufzuteilen halte ich nur bedingt für sinnvoll. Dann müsste man das 
strenggenommen für jedes Modul machen welches zu unterschiedlichen 
Platformen passt (also z.b. UART_AVR.c/h; UART_WIN32.c/h; UART_ARM.c/h 
oder MMC_AVR.c/h; MMC_PIC.c/h; MMC_WIN32.c/h usw ...) Dann explodiert 
der Ordner irgendwann.
Sinniger wäre es vllt (zumindest gehe ich langsam dazu über das so zu 
machen) die platformabhängigen Teile in dem jeweiligen Modul selbst zu 
integrieren. Also das eine MMC.c/h oder UART.c/h alle Funktionen für 
alle (!!) Platformen beinhaltet.
Das macht die Sache zwar nicht übersichtlicher, aber ich weiß nicht was 
unübersichtlicher ist : Wenige Module mit vielen Abschnitten, oder viele 
Module mit nur einem Abschnitt.
Wie man es letztenendes realisiert ist denke ich Geschmackssache. Der 
Quellcode dafür muß ja ohnehin für jede Platform irgendwo vorhanden 
sein. Also warum nicht im Modul selbst ?!

Danke noch für deine Mühe das Ganze für das XPlain Board anzupassen.


@uwe

Bin mal gespannt auf deine Änderungen. Werd mir mal das SVN 
aktualisieren.


@All

Habt ihr eig. schon eine Verwendung für das Basic (egal ob von Uwe, mir 
oder sonstwem) ? Was habt ihr mit dem Basic vor ? Habt ihr es schon 
getestet ?

Mich würde es freuen etwas Feedback zu dem Thema zu bekommen.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Rene Böllhoff schrieb:
> @uwe
>
> Bin mal gespannt auf deine Änderungen. Werd mir mal das SVN
> aktualisieren.
>
ein paar Anregungen zu den aktuellen Änderungen habe ich aus deiner 
letzten Version gewonnen...

Grüße Uwe

von Rene B. (themason) Benutzerseite


Lesenswert?

@Uwe

Freut mich wenn jemand Teile oder Ideen aus meinem Code weiterverwenden 
kann :-)

Mal schauen ob ich deine Umsetzungen finde :-))

Gruß
Rene

von chris (Gast)


Lesenswert?

>Also die platformspezifischen Unterschiede auf mehrere Dateien
>aufzuteilen halte ich nur bedingt für sinnvoll. Dann müsste man das
>strenggenommen für jedes Modul machen welches zu unterschiedlichen
>Platformen passt (also z.b. UART_AVR.c/h; UART_WIN32.c/h; UART_ARM.c/h
>oder MMC_AVR.c/h; MMC_PIC.c/h; MMC_WIN32.c/h usw ...) Dann explodiert
>der Ordner irgendwann.

Ja, es stimmt, die Anzahl der Dateien steigt mit jeder Plattform an. Am 
besten wäre es, für jede Plattform einen Unterordner anzulegen.
Das von Dir beschriebene Beispiel passt gut: Die Uart ist ja wirklich 
bei jeder Plattform völlig verschieden. Also muss man den Code für jede 
Plattform so oder so erstellen. Hilfreich ist da ein gemeinsames 
Headerfile
1
platform_specific.h

in diesem File steht dann der Prototyp für die UART z.B.
1
void platform_putchar(uint8_t zeichen);

Die dann im Plattformfile "platform_WIN32.c" für den PC so aussieht:
1
void platform_putchar(uint8_t zeichen)
2
{
3
 putchar(zeichen)
4
}

So umständlich es scheinen mag, so praktisch ist es: die Plattform 
spezifischen Funktionen sind wirklich vom eigentlichen Programm getrennt 
und damit wird das BASIC wirklich portabel.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

im SVN von mikrocontroller.net ist eine neue Version des 
Basic-Interpreters (mein Entwicklungszweig...) verfügbar:

http://www.mikrocontroller.net/svnbrowser/avr-basic/

U.a. sind folgende Änderungen eingeflossen:

* Erweiterung/Verbesserung des Basic-Syntax:
  *berechenbare Sprungziele in einer Reihe von Basic-Befehlen
  *Verbesserung PRINT-Anweisung
  *Kurzform für if-then (then kann weggelassen werden)

* die wichtigste Änderung: der Basic-Quelltext kann von einem beliebigen 
Speichermedium eingelesen werden. Dazu gibt es ein paar Defines, welche 
entsprechend umdefiniert werden müssen. Im Archiv sind 3 Beispiele für 
Speichermedien enthalten.

* Anpassung der Dokumentation

Grüße Uwe Berger

von Rene B. (themason) Benutzerseite


Lesenswert?

Werde ich mir direkt mal anschauen :-)

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

eine neue Version ist im SVN 
(http://www.mikrocontroller.net/svnbrowser/avr-basic/uwe_berger/) 
verfügbar:

-Bugfix in ubasic_call.c und ubasic_cvars.c (es gab einen Seg. fault, 
wenn Prozedure bzw. Variable nicht definiert, aber doch angesprochen 
wurde...)

-neue Zahlenformate: Hexadezimal und Dual

-Doku entsprechend angepasst.


Grüße Uwe Berger

von Uwe B. (boerge) Benutzerseite


Angehängte Dateien:

Lesenswert?

MoinMoin,

ich habe mal mit meiner Basic-Interpreter-Lib ein kleines 
Referenz-Projekt erstellt (siehe Anhang):

* die Basic-Programme liegen auf einer SD-Karte und werden während der 
Interpretation auch direkt von dort gelesen; damit wollte ich vor allem 
testen, ob meine letztens implemtierte Schnittstelle zum Zugriff auf 
beliebige Speichermedien auch wirklich funktioniert... (und ja, sie 
funktioniert!)

* als SD-Karten-Lib ab ich 
http://www.mikrocontroller.net/articles/AVR_FAT32 verwendet

* Ein-/Ausgabe erfolgt über die serielle Schnittstelle

* ein ATmega168, wie ich ihn bisher verwendet habe, stößt jetzt an seine 
Grenzen (SRAM); es laufen nicht mehr alle Basic-Programme, die ich zum 
Testen verwendet hatte, weil teilweise der dynamische Speicher zu klein 
ist; habe mir deswegen auch gerade ein paar ATmega328 bestellt...

* in Punkto Ausführungsgeschwindigkeit ist der Interpreter natürlich 
langsamer geworden, was am Speichermedium SD-Karte und der 
entsprechenden Lib liegt (was jetzt aber keine Kritik an Daniel sein 
soll!); ich hatte auch nichts anderes erwartet

* eine "Doku" befindet sich am Anfang von main.c

Ausblick, wenn ich dann einen ATmega328 in der Hand haben sollte:
* Grafik-Display oder TV-Out
* PC-Tastatur
(...eigentlich wollte ich keinen Basic-Computer aufbauen/implementieren, 
aber irgendwie reizt es doch...)

Grüße Uwe

von chris (Gast)


Lesenswert?

Vorschlag zum RAM-Problem:

Was hältst Du von einem Treiber für ein serielles RAM wie das 23x256 von 
Microchip:
ww1.microchip.com/downloads/en/DeviceDoc/22100D.pdf

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

chris schrieb:
> Vorschlag zum RAM-Problem:
>
> Was hältst Du von einem Treiber für ein serielles RAM wie das 23x256 von
>
zum Zwischenspeichern des Basic-Programmes? Prinzipiell ja, es müssten 
dann nur die Defines in tokenizer_access.* entsprechend angepasst 
werden.

Dann stellt sich aber die Frage, wie das Basic-Programm in den SRAM 
kommt...

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

... nochmal zum Thema externer SRAM:

Mir ist gerade der "bekloppte" Gedanke gekommen, die ganzen internen 
Stacks/Caches des Interpreters (GOSUB-, FOR/NEXT-Stack und den 
GOTO/GOSUB-Cache) dorthin auszulagern. Man könnte eine ähnlich 
universelle Schnittstelle, wie für das Speichermedium der 
Basic-Programme schreiben...

Allerdings würde dabei auch ein gewisser Overhead entstehen, der sich 
wahrscheinlich mit dem gewonnenen SRAM im MC die Waage hält, aber dafür 
könnte man die Größen der Stacks/Caches drastisch erhöhen... Die 
Ausführungsgeschwindigkeit des Interpreters dürfte sich vermutlich 
entscheidend verschlechtern.

Für Rene's Pre-Compiler wäre die Geschichte aber gar nicht so 
uninteressant, weil dann der vorübersetzte Code auch dorthin ausgelagert 
und im 2.Lauf von dort wieder eingelesen werden könnte. Rene, was meinst 
du dazu?

Grüße Uwe

von Rene B. (themason) Benutzerseite


Lesenswert?

Ich hatte noch ne viel beklopptere Idee :-)

Meine Idee war/ist das ich neben dem Basic ein Dateisystem aufziehe 
indem alle möglichen Medien (zu denen es Treiber gibt) integriere und 
quasi eine Oberfläche damit bilde. Dadurch das die Programme ja auch mit 
meiner Version compilierbar sind ist es letztenendes egal wo das 
Programm (Compiliert oder uncompiliert) landet. Also ein Basic-Programm 
ist auf SD-Karte und wird compiliert und in ein Datenflash abgelegt. 
Dadurch das der Basic-Byte-Code relativ schnell ausgeführt werden kann 
hätte man da einiges an Möglichkeiten, und könnte sich nach und nach ein 
System aufbauen.

Ich hab auch die Idee Basic-Programme als Unterprogramme ausführen zu 
lassen.
Bsp :

SD-Karte :
Main.bas
UP1.bas

in Main.bas steht bspweise :

...
230 call ("UP1.bas", a = 20, b = 40, c = 50)
...

Das UP1.bas wird geladen, die Variablen a b und c initialisiert und 
UP1.bas dann ausgeführt. Ist UP1.bas dann beendet kehrt die 
Programmbearbeitung zur nächsten Zeile nach dem Call zurück.
Im Prinzip ist das auch relativ einfach machbar (auch bei Uwe müsste 
sich das einfach nachrüsten lassen soweit ich seinen Quellcode gesehen 
habe).
Da gibts bestimmt noch ein paar andere schöne Ideen (z.b. das 
Dateisystem ähnlich wie in Linux mit Ein/Ausgabegeräten versehen).
Langfristig werde ich sicherlich diese Ideen (bzw die ein oder andere 
davon) umsetzen.
Allerdings ist es ja auch immer eine Frage des Speicherplatzes, und ich 
denke bei solchen möglichkeiten werden selbst 32K eng. Es sei denn man 
macht alles in Assembler. Aber dafür ist der Jörg Wunsch mit seinem 
genialen AVR-ChipBasic zuständig :-)

von chris (Gast)


Lesenswert?

"... nochmal zum Thema externer SRAM:

Mir ist gerade der "bekloppte" Gedanke gekommen, die ganzen internen
Stacks/Caches des Interpreters (GOSUB-, FOR/NEXT-Stack und den
GOTO/GOSUB-Cache) dorthin auszulagern. Man könnte eine ähnlich
universelle Schnittstelle, wie für das Speichermedium der
Basic-Programme schreiben..."

Sehr gut. Ins RAM müssen ja nur veränderbare Variablen. Das eigentliche 
Basic-Programm kann ja auf einer SD-Karte residieren. Damit dürfte es 
dann möglich sein, ziemlich große BASIC-Programme laufen zu lassen.
Was die Geschwindigkeit anbelangt, wäre ich mir nicht so sicher, ob das 
Ganze wirklich so langsam wird. Theoretisch könnte man das RAM oder die 
SD-Karte im Block-Mode auslesen, also z.B. immer 128Byte und dann so 
eine Art Cache implementieren.

von Rene B. (themason) Benutzerseite


Lesenswert?

@chris

Da wäre dann aber der Ansatz mit dem Vorcompilieren noch deutlich 
schneller, da die komplette Text-erkennung entfällt, und die 
Gosub/Goto-Sprungziele vorher schon ermittelt werden und dann quasi in 
"Null-Zeit" angesprungen werden können. Bei der Ursprungsvariante wurde 
bei einem Gosub/Goto ja das gesamte Programm von vorne durchsucht. Die 
Caches beschleunigen das ganze erheblich. Aber der Ansatz des 
vorcompilierens dürfte unschlagbar schnell sein :-)
Nur ist der "Text" danach eben nicht mehr lesbar. Es sei denn ....

von chris (Gast)


Lesenswert?

Also beim ZX81 gab es einen Tokenizer, der hat die Texterkennung 
übernommen. Da der Computer nur 1K SRAM hatte und die Hälfte davon in 
der Basisversion noch als Bildschirmspeicher benutzt hat, wurde das 
gesamte Programm "tokeniziert" abgespeichert. Mit dem Befehl "list" 
wurde dann das Programm wieder lesbar dargestellt.

von Rene B. (themason) Benutzerseite


Lesenswert?

Mmh ... Einen Tokenizer ohne wirklich Speicher zu verbrauchen ... 
Erinnert mich irgendwie an meinen ersten Parser uShell :-)
Der kam (bzw kommt) mit sehr wenig RAM aus um ein Token zu erkennen 
(etwa : (Anzahl Tokens / 8) + 2).

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

Rene Böllhoff schrieb:
> Ich hab auch die Idee Basic-Programme als Unterprogramme ausführen zu
> lassen.
>
die Anfrage wurde auch schon von jemanden aus der c't-Bot-Ecke, wo der 
Basic-Interpreter derzeit im Develop-Zweig integriert ist, an mich 
herangetragen... Ich habe erst mal abgewiegelt, weil:

Es müsste so ziemlich alles, was im aufrufenden Programm an dynamischen 
Werten (Rücksprungadresse, for/next-Stack, Gosub-Stack, 
Goto-Gosub-Cache, die 26 Variablen usw.) angefallen ist, in einen Stack 
wandern. Lustig wird die Geschichte, wenn vom Unterprogramm noch weiter 
verschachtelt wird...

Achso, und es müsste wahrscheinlich eine SD-Lib her, wenn man denn z.B. 
mit dem Medium arbeiten will, die das gleichzeitige Öffnen von mehreren 
Files ermöglicht. Die ich gestern verwendet habe kann es nicht, da 
müsste man tricksen.

Das alles dürfte für einen AVR SRAM-mäßig zuviel werden, es sei denn man 
verwendet einen Mega1284 (gibt es den schon zu kaufen?) oder einen 
exteren RAM...

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

chris schrieb:
> Sehr gut. Ins RAM müssen ja nur veränderbare Variablen. Das eigentliche
> Basic-Programm kann ja auf einer SD-Karte residieren. Damit dürfte es
> dann möglich sein, ziemlich große BASIC-Programme laufen zu lassen.
>
mittlerweile finde ich die Idee auch nicht mehr soooo bekloppt. Es gibt 
nicht allzu viele Stellen im Quelltext, wo auf interne "Stack-Bereiche" 
zurückgegriffen wird. Ich muss mal eine Weile darüber nachdenken, wie 
eine universelle Schnittstelle, ähnlich wie das Einlesen des 
Basic-Programms, aussehen müsste.

Große Basic-Programme...: der meiste Speicher wird durch die vielen 
Rekursionen in ubasic.c verbraten, den man nicht auslagern kann. 
Typisches Beispiel dürfte eine Expression sein, die mit mehreren 
Klammern ausgestattet ist...

chris schrieb:
> Was die Geschwindigkeit anbelangt, wäre ich mir nicht so sicher, ob das
> Ganze wirklich so langsam wird.
>
naja, kommt halt wieder auf das Speichermedium an, bei dem oben 
erwähnten seriellen RAM dürfte es schon einiges an Zeit kosten, die 
Werte auszulagern bzw. wieder einzulesen...

Grüße Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Uwe Berger schrieb:
> Es müsste so ziemlich alles, was im aufrufenden Programm an dynamischen
> Werten (Rücksprungadresse, for/next-Stack, Gosub-Stack,
> Goto-Gosub-Cache, die 26 Variablen usw.) angefallen ist, in einen Stack
> wandern. Lustig wird die Geschichte, wenn vom Unterprogramm noch weiter
> verschachtelt wird...
>
ähmm, nochmal zu dem Thema und ganz wage formuliert...:
ein Kompromiss wäre doch eigentlich, die Stack-Bereiche einfach gültig 
zu halten und weiter zu verwenden. Ein Unterprogramm ist doch nichts 
weiter als quasi eingeschobener Quelltext. Also alte Datei zu, neue 
Datei auf und weiterlesen usw., als wenn alles ein einziges Programm 
wäre... Die Zeilennummern sollten aber eineindeutig sein und eine 
Variablenübergabe, wie sie Rene vorschwebt geht dann bestimmt auch 
nicht, plus einiger weiterer Problemchen, die ich noch nicht benennen 
kann (den Textpointer des aufrufenden Programms müsste man sich 
vielleicht irgendwie doch merken).

Grüße Uwe

PS.: und es geht nur mit einem Speichermedium, auf dem ich den 
Programmen auch einen vernünftigen Namen geben kann, irgendwelche 
Speicherbereiche mit komischen Zeigern fallen dann aus...

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

Uwe Berger schrieb:
> ähmm, nochmal zu dem Thema und ganz wage formuliert...:
> ein Kompromiss wäre doch eigentlich, die Stack-Bereiche einfach gültig
> zu halten und weiter zu verwenden. Ein Unterprogramm ist doch nichts
> weiter als quasi eingeschobener Quelltext.
>
nach dem ich mal eine Nacht drüber geschlafen habe, gefällt mir diese 
Idee immer besser. Am besten würde die Geschichte zum GOSUB-Befehl 
passen, der dann 2 Varianten aufweisen würde:

10 GOSUB 1000
20 GOSUB "up.bas"

10: wie bisher als Zeilennummer
20: Erkennung eines Strings, statt einer Zeilennummer; Dateiname des UPs

GOSUB deshalb:
* erscheint vom Syntax am logischsten (wenn man keinen neuen Befehl 
kreieren will)

* in den entsprechenden Routinen (gosub-/return-Statement) werden 
eigentlich schon die entsprechenden Stack-/Cache-Bereiche verwaltet, die 
nur noch nur noch um den UP-Namen aufgebohrt werden müssten.

Ein UP übernimmt die Variableninhalte des aufrufenden Programms und 
müsste natürlich mit einem RETURN enden. Eineindeutige Zeilennummern, 
sind wahrscheinlich doch nicht nötig, da die erweiterten 
Stack-/Cache-Bereich auch den UP-Namen enthalten müssen und damit wieder 
eineindeutig werden.

Ich denke ich werde das mal zuende denken und in meiner 
Interpreterversion einbauen...

Grüße Uwe

von Rene B. (themason) Benutzerseite


Lesenswert?

@Uwe

Diese ganzen gedanklichen Ergüsse hatte ich ebenfalls bei der Überlegung 
:-)
Das mit der SD-Lib hätte ich fast vergessen. Aber bei meinen 
Vorüberlegungen hatte ich mir ohnehin eine eigene FAT-Lib 
zusammengeschrieben weshalb das ganze Projekt auch ein wenig 
eingeschlafen ist. Bin beim programmieren von Höksken auf Stöcksken 
gekommen (AVR-Basic -> FAT-Lib) (FAT-Lib -> SD_Core für FPGA) (SD_Core 
für FPGA -> eigener Prozessor) (eigener Prozessor -> eigener Assembler). 
Irgendwie kein Wunder warum ich mit meinen Projekten nie 100% fertig 
werde (abgesehen von so Mini-Projekten) :-)

>Es müsste so ziemlich alles, was im aufrufenden Programm an dynamischen
>Werten (Rücksprungadresse, for/next-Stack, Gosub-Stack,
>Goto-Gosub-Cache, die 26 Variablen usw.) angefallen ist, in einen Stack
>wandern.

Da hab ich auch zuerst mit ein wenig Bauchschmerzen gehabt. Aber bei 
meiner Variante fällt das etwas leichter, da ich keinen Goto/Gosub-Cache 
habe. Und die 26x2 Bytes Variablen-Stack, For/Next und Gosub-Stack pro 
Programmaufruf sind zwar auch nicht wenig, aber evtl wäre da eine 
"dynamische" Variablenverwaltung ala DIM sinnvoll, denn man benötigt ja 
nur in wenigen Fällen alle 26 Variablen. Meist sind es ja weniger. Und 
je nachdem wie man sich das Variablen-System zurechtlegt (also den 
Programmkontext) spart man sogar noch gegenüber der Brute-Force-Methode 
alle 26 Variablen immer abzuspeichern, bzw vorzuhalten.

>einen Mega1284 (gibt es den schon zu kaufen?)

Jup, gibt es. Hatte auch gehofft das der schon Mitte letzten Jahres 
rausgekommen wäre (mir 64kB kam ich schnell an die grenzen meines 
Audio-Projektes). Mit den 16kB RAM lässt sich schon ne ganze Menge 
anstellen. Nur wäre es sehr doof wenn das Basic (obwohl soviel 
Flexibilität) nur auf einem einzigen AVR laufen würde.

>der meiste Speicher wird durch die vielen Rekursionen in ubasic.c
>verbraten, den man nicht auslagern kann.

Da hab ich im Endeffekt auch mehr bauchschmerzen gehabt als bei den 
anderen Betrachtungen.
Aber mit dem Auslagern wäre ich mir nicht so sicher das das nicht doch 
"einfach" machbar ist :-)))). Ich habe da eine ziemlich perverse Idee. 
Ich muß die nochmal reifen lassen, aber wenn das klappt dann .... :-)

>Typisches Beispiel dürfte eine Expression sein, die mit mehreren
>Klammern ausgestattet ist...

Genau dieses Problem hab ich (in einem kleinen Experimentier-Projekt) 
vollständig OHNE rekursive Aufrufe hinbekommen. Erzähl ich mal mehr wenn 
die Idee noch was weiter gereift ist. Der Ansatz ist denke ich nicht 
schlecht, und erlaubt auch eine grundlegende Kontrolle die bei allen 
Rekursionen NICHT möglich ist :-) Das Stichwort ist da : 
"Stack-Overflow" passe ...

>naja, kommt halt wieder auf das Speichermedium an, bei dem oben
>erwähnten seriellen RAM dürfte es schon einiges an Zeit kosten, die
>Werte auszulagern bzw. wieder einzulesen...

Daher hab ich mir auch eine eigene AVR-Basic-Projekt-Platine gebastelt 
mit 512k SRAM, (später noch mit HDD) und einem Grafik-Display. Aber das 
ganze hat sich ja leider etwas nach "hinten" verschoben.

>PS.: und es geht nur mit einem Speichermedium, auf dem ich den
>Programmen auch einen vernünftigen Namen geben kann, irgendwelche
>Speicherbereiche mit komischen Zeigern fallen dann aus...

Nicht zwangsweise. Daher habe ich bei meiner Variante auch vorwiegend 
den Datentyp INT (16-bit) verwendet. Wenn ich das noch richtig im Kopf 
habe, habe ich alles auf INT umgestellt mit der Bedeutung das sich INT 
immer relativ auf den Anfang des Textes bezieht. Damit sind Speicher 
ebenso wie Dateien direkt gleich behandelbar. Und bei Fehlern lässt sich 
leicht die Stelle im Text ermitteln an der es gekracht hat.

>nach dem ich mal eine Nacht drüber geschlafen habe, gefällt mir diese
>Idee immer besser.

Ging mir ähnlich :-))

>Ein UP übernimmt die Variableninhalte des aufrufenden Programms und
>müsste natürlich mit einem RETURN enden.

Auch nicht zwnagsweise :-)
Da der interpreter das Programmende ja erkennt muß er nur (wenn es nicht 
das Hauptprogramm ist) ganz normal in das alte Programm zurückkehren.
Ich hatte mir neben dem übergeben von Variablen an das Unterprogramm 
auch überlegt das man Variablen VOM UP ans HP zurückübergeben kann. 
Müsste da aber nochmal genauer überlegen. Hatte mir da schon einen 
schicken Lösungsansatz überlegt, aber die Idee irgendwie verlegt :-))

>da die erweiterten
>Stack-/Cache-Bereich auch den UP-Namen enthalten müssen

Ich denke in deinem Falle wäre ein eigener Kontext sinnvoller, da du 
dich dann nicht um eineindeutigkeit und evtl Löschen von Cache Einträgen 
vornehmen musst um nicht im weiteren Programmverlauf auf die Nase zu 
fallen. Dann wirds denke ich aufwendig.

Eig. könnte man (wenn es nicht doch einige größere Unterschiede gäbe) 
die beiden Versionen ohne weiteres zusammenführen. Aber von den 
unterschiedlichen Ansätzen profitieren denke ich alle. Deine Version ist 
einfach und kompakt gehalten. Meine eben etwas "aufgeblähter", aber 
dafür auch mit einigen mächtigen Features.

PS. Ich habe das Gefühl das ich die Idee mit dem Gosub 10+20+3*(a) 
ebenfalls mit bei mir implementieren könnte. Ich müsste zwar dann 
jedesmal suchen, aber in der vorcompilierten Form wäre das denke ich 
auch zeitlich einigermaßen machbar.

PPS. Immer weiter so Uwe :-) Ich werd mich auch wieder in absehbarer 
Zeit mit daran beteiligen.

von chris (Gast)


Lesenswert?

Wenn Ihr nicht zu sehr auf die Geschwindigkeit achten müsst, dann wäre 
ein serielles SRAM ganz toll. Viellicht noch in Kombination mit einem 
seriellen EEPROM oder eben SD-Karte
Die resultierende Platine würde sehr klein, z.B. Atmega168+serielles 
SRAM und könnte ordentliche Programme ausführen.
Man wäre dann ( falls es nicht um die Geschwindigkeit geht) nicht von 
Spezialprozessoren wie den Atmega1284 angewiesen.
Wenn ich mich nicht täusche war das die Arbeitsweise der Basic-Stamp und 
dem Basic-Tiger.

von Rene B. (themason) Benutzerseite


Lesenswert?

@Chris

Die Idee mit dem seriellen SRAM finde ich gar nicht mal schlecht. Ich 
überlege schon die ganze Zeit wo ich mein FRAM mal verwenden kann :-)
Ne, mal im Ernst. Ich denke FRAM wäre das beste. Da es die FRAMs ja zw 
8-64kB (oder größer) gibt hätte man die Möglichkeit einfach Programme 
abzulegen und hätte gleichzeitig noch irre viel SRAM für Variablen, 
Stacks usw. Die Geschwindigkeit ist dann zwar nicht mehr so berauschend, 
aber wenn man entweder damit leben kann, oder aber mit vorcompilierten 
Texten arbeitet hält sich die Geschwindigkeitseinbuße in grenzen. Oder 
aber wie von dir schon vorgeschlagen einen kleinen "Seiten-Cache", wobei 
die Ausführung dadurch ja auch nicht wirklich schneller wird, da man ja 
ohnehin erst immer eine Seite einlesen muß. Wäre dann mal durch 
Performancemessungen zu ermitteln.
Wenn du eine Platine machen lässt sag mal bescheid :-)
Zum experimentieren wäre aber vllt ein Mega328 evtl sinnvoller. Man 
hätte immer noch etwas "Reserven" nach oben, und ich denke bei diesem 
Projekt wo im Laufe der Zeit immer mehr an Features dazukommt kann das 
nicht verkehrt sein.

von chris (Gast)


Lesenswert?

"Die Geschwindigkeit ist dann zwar nicht mehr so berauschend"

Hängt die Geschwindigkeit nicht vom Verhältnis 
Interpreter/Speicherzugriff ab?
Ich vermute, dass die Interpretation eines Befehls mindestens so lange 
geht wie ein Speicherzugriff. D.h. würde die Sache vielleicht nur halb 
so schnell.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

MoinMoin,

habe gerade die "Weihnachtsversion" meines Entwicklungszweiges ins SVN 
eingespielt. Folgende wesentlichen Änderungen/Neuerungen:

- Erweiterung des GOSUB-Befehls, es können externe Unterprogramme 
geladen/ausgeführt werden

- Dateien/Verzeichnisse neu strukturiert

- SD-Karten-Version jetzt im Zeig mit enthalten (SD-Karten-Lib: 
http://www.roland-riegel.de/sd-reader/index.html)

- Dokumentation entsprechend angepasst


Grüße & ein ruhiges Weihnachtsfest,
Uwe

von Rene B. (themason) Benutzerseite


Lesenswert?

Wow,

ich glaub ich muß demnächst auch mal wieder nachlegen :-)

Sehr schön gemacht. Hab mir zwar die Quellcodes noch nicht weiter 
angeschaut, aber schön das das Unterprogramm-Feature nun auch mit drin 
ist.
Weiter so. Bei mir wirds wahrscheinlich noch etwas dauern, da ich noch 
einige
andere Ideen in der Richtung verfolge die evtl auch mit in das Basic
einfließen werden.

Dir Uwe, aber auch allen anderen ein frohes besinnliches und friedliches 
Weihnachtsfest und ruhige Feiertage.

Rene

von basicfan (Gast)


Lesenswert?

Hallo, schönes Ding was ihr ausgetüftelt habt.

Nun, wie kann man eigentlich Basicprogramme über das Terminal 
rüberschieben?

Ich benutze zur Zeit eine SD-Karte.

Gruss

von Uwe B. (boerge) Benutzerseite


Lesenswert?

basicfan schrieb:
> Nun, wie kann man eigentlich Basicprogramme über das Terminal
> rüberschieben?
>
na das liegt ganz an deinen Programmierkünsten und was du um den 
Basic-Interpreter herum implementierst. Was du in den Archiven findest, 
sind nur Beispiele, was man mit dem Ding machen könnte...

> Ich benutze zur Zeit eine SD-Karte.
>
na ist doch schon mal ein Anfang und als Speichermedium hervorragend 
geeignet. Vielleicht jetzt noch eine kleine Routine, die Daten über die 
serielle Schnittstelle empfängt und auf der Karte abspeichert...? Oder 
doch gleich einen kleinen Editor auf dem MC (analog dem ChipBasic von 
Wolfram)...?

Grüße Uwe

von basicfan (Gast)


Lesenswert?

hmmm..., ich glaubte irgendwo etwas gelesen zu haben, das man 
Daten/Programme bei diesem Basic über aRS232 rüberschieben kann.

Na mal schauen.
Ihc bin nämlich kein Programmierkünstler in "C" mit 62 jahren...

Vielleicht gibt es bald eine Erweiterung oder ein Tipp dafür.
Ich finde keinen zur Zeit keinen Ansatz, wo man das Gerüst reinsetzen 
soll, und wie es die Daten schieben soll.

Vielleicht gibt es etwas für den AVR1284p mit 16kb SRam.
Damit könnte man auch etwas anstellen.

Gruss

von basicfan (Gast)


Lesenswert?

Ah...., habe die Quelle jetzt gefunden:
hier: http://bralug.de/wiki/UBasic-avr
...Über die serielle Schnittstelle können zu Testzwecken Basic-Programme 
geladen und gestartet werden (gesteuert über die Hauptschleife im 
Testprogramm). Die Ausgaben (PRINT-Befehl, Debug-Ausgaben) erfolgen 
ebenfalls über diese Schnittstelle....

Das wollte ich Testen mit der RS232.
Gibt es das Programm noch irgendwo?

Gruss

von basicfan (Gast)


Lesenswert?

...Als Referenz für das Einbinden des Basic-Interpreters in eigene 
Programme, ist das Studium von main.c, welche im Quellcode-Archiv 
enthalten ist, angeraten....

Hmm..., die main.c finde ich nicht im Ordner.

Gruss

von basicfan (Gast)


Lesenswert?

...Da wird der BB erst langsam Munter ;)...
ist ein bisschen teuer das Ding.

Gruss

von basicfan (Gast)


Lesenswert?

Hallo, wie sieht hier die " MAKEFILE" aus :
----------------------------
Autor: TheMason (Gast)
Datum: 02.07.2010 17:27
Angehängte Dateien:

* ubasic-0.2a.zip (24.5 KB, 30 Downloads) >>>> "MAKEFILE" ?
-------------------------------

Danke.

Gruss

von TheMason (Gast)


Lesenswert?

@basicfan

Wenn du meine Version hast (uBasic0.2a) macht AVR-Studio das Makefile. 
Daher hab ich mir das hier "geschenkt", da ich auch nur mit AVR-Studio 
arbeite. Wenn Fragen zur Version von "TheMason" (myself) sind, frag 
ruhig. :-)

von basicfan (Gast)


Lesenswert?

Kannst du die hier mal als Beispiel reinstellen, damit ich dein Programm 
mal zum laufen bringe.
Ich compiliere nur mit dem Notepad von Winavr.

Gruss

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Hallo basicfan,

wie schon erwähnt, es handelt sich um eine Bibliothek, die man in eigene 
Applikationen einbinden kann. Sämtliche Beispiele sollen nur die 
Möglichkeiten aufzeigen und zu eigenen (Programmier-)Experimenten 
anregen.

basicfan schrieb:
> Hmm..., die main.c finde ich nicht im Ordner.

Ich hatte letztens (meinen) Quellcode etwas umstrukturiert, das 
"zitierte" Beispiel gibt es der Form nicht mehr, da in ihm auf eine 
Systematik aufgesetzt wurde, die sehr viel dynamsichen RAM verbraucht 
hatte.

In der SVN-Version 27 findest du in meinem Verzeichnis noch main.c, 
welche die Datenübertragung via serieller Schnittstelle beinhaltet. Aber 
ohne dein Zutun wird da nichts auf einer SD-Karte abgespeichert, kann 
also nur als Anhaltpunkt für deine Weiterentwicklungen dienen...!

Grüße Uwe

von basicfan (Gast)


Lesenswert?

...In der SVN-Version 27 findest du in meinem Verzeichnis noch 
main.c,...

Wie komm ich da ran?
Es ist nur die neueste Version drauf, oder bin ich da falsch?

Gruss

von Uwe B. (boerge) Benutzerseite


Lesenswert?

basicfan schrieb:
> Wie komm ich da ran?
> Es ist nur die neueste Version drauf, oder bin ich da falsch?
>
SVN ist ein Versionsverwaltungssystem innerhalb dem man auf alle jemals 
eingespielte Versionen zugreifen kann, also auch auf nicht mehr aktuelle 
Versionen.

Klicke im Webfrontend auf die Revisionsnummer (derzeit die 31), dann 
erhält man eine Liste aller Versionen, dort dann auf die Revision 27. In 
dieser Version gab es das letzte mal eine Änderung in der Datei 
main.c...

Aber diese main.c kannst du nicht einfach mit der aktuellen Version der 
Bibliothek mischen! Man könnte aber dort beispielhaft sehen, wie man 
Basic-Programme über die serielle Schnittstelle auf den Mikrocontroller 
bekommt, wobei sie aber nicht auf einer SD-Karte, sondern in einem 
RAM-Bereich des MC abgelegt werden.

D.h. also du musst schon etwas Programmierkunst anwenden, um das zu 
erreichen, was du gern möchtest...

Aber warum steckst du deine SD-Karte nicht einfach in einen Kartenleser 
am PC rein und speicherst die Programme so ab?

Grüße Uwe

von basicfan (Gast)


Lesenswert?

...Aber warum steckst du deine SD-Karte nicht einfach in einen 
Kartenleser
am PC rein und speicherst die Programme so ab?....

Das mach ich auch und das Basic funktioniert mit meinem selbstgebauten 
Terminal von Purebasic wunderbar.

Ich bin halt neugierig wie es machbar wäre.

Danke.

gruss

von Rene B. (themason) Benutzerseite


Lesenswert?

@basicfan

Der Ansatz ist ein anderer. Es geht sich darum das Basic in ein 
bestehendes System zu integrieren. Die Idee mit der "ladbarkeit" von 
SD-Karte kam später durch ein paar "Spinnereien" zw Spielereien von Uwe 
und mir.
Der eigentliche Fokus liegt also nicht auf dem Basic als 
Stand-Alone-Projekt, sondern vielmehr als Grundgerüst um es in 
bestehende Projekte einzubauen.

von basicfan (Gast)


Lesenswert?

.....
#ifndef _UBASIC_CONFIG_H_
#define _UBASIC_CONFIG_H_


// AVR-spezifischen einschalten
#ifndef USE_AVR
  #define USE_AVR    1
#endif

// regulaere Standardausgabe
#if USE_AVR
  #define PRINTF(...)  usart_write(_VA_ARGS_)
#else
  #define PRINTF(...)  printf(_VA_ARGS_)
#endif

// grml..., sollte man besser loesen!
#if !USE_AVR
  #define uint8_t unsigned char
#endif

// max. Stringlaenge (Basic)
#ifndef MAX_STRINGLEN
  #define MAX_STRINGLEN 20
#endif
......

Benutze jetzt die SVN-Version 27, ist schön übersichtlich um diesen 
Interpreter kennenzulernen.

Frage:
Wie werden eigentlich diese vielen "#ifndef" freigegeben damit die 
benutzt werden?

gruss

von TheMason (Gast)


Lesenswert?

Die #ifndef sind ja eigentlich nur drin, damit Standardwerte vorhanden 
sind. Das man Quasi direkt "loslegen" kann. Wenn du andere Werte haben 
willst musst du bevor du die basic.h (und damit auch die config-Datei) 
inkludierst diese definieren.
So würde ein

#define MAX_STRINGLEN 40

den Standardwert 20 für MAX_STRINGLEN "überschreiben".

>Benutze jetzt die SVN-Version 27, ist schön übersichtlich um diesen
>Interpreter kennenzulernen.

Schau dir dann besser nicht meinen Zweig an, da wirds dann sehr hässlich 
:-) und das obwohl es diesselbe Basis ist.

Aber dafür bekommt man ja auch noch ein paar nette Zusatzfeatures. 
Allerdings ist das wirklich nicht einfach zu lesen !

von TheMason (Gast)


Lesenswert?

Nachtrag :

Die ifndefs müssen nicht "freigegeben" werden. ifndef sagt nur aus wenn 
das Symbol hinter ifndef nicht (!) definiert ist so "blende" den Teil 
hinter dem ifndef bis zum nächsten ifdef/endif/elsif ein.
Schau dir das mal bei den Headern an. Da hat das den hintergrund das 
nicht zweimal derselbe Header "eingefügt" wird.
Alle #-"Anweisungen" sind nur für den Präprozessor der reine 
Text-ersetzung macht. Der Präprozessor weiß nichts von C oder 
irgendwelchen "Freigaben". Es können beim Compilieren bestenfalls ein 
paar vordefinierte Symbole mit übergeben werden. Aber was der 
Präprozessor daraus macht hängt von den #-Anweisungen ab.

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.