Forum: Mikrocontroller und Digitale Elektronik Kommandoshell für µC: selber schreiben oder Parsergenerator (Flex/Bison bzw. GOLD)?


von Ralf (Gast)


Lesenswert?

Hallo,

ich beschäftige mich gerade mit der Thematik, Befehle an einen µC zu 
senden. Im kleinen Rahmen konnte ich mir bisher immer damit behelfen, 
einzelnen Zeichen bestimmte Funktionen zuzuordnen. Das aktuelle Projekt 
ist ein bisschen größer (geworden als ich dachte), und da wäre eine 
Befehlsverarbeitung mit Parametern geschickter.

Je mehr ich nun versuche, in die Thematik zu kommen, desto verwirrender 
wird's momentan: suche ich nun einen Interpreter, einen Parser, eine 
Commandshell oder einen Mix aus allem? Soweit ich es verstanden habe, 
sind diese Begriffe nicht unbedingt Synonyme für ein und dasselbe.

Von der Art her hätte ich's gern ála Kommandokonsole. Was mir 
vorschwebt, wäre z.B. Unterstützung von Umgebungsvariablen, die man auch 
als Parameter an Kommandos weitergeben kann, und die Möglichkeit, 
Befehle bzw. mathematische Ausdrücke/Formeln, die einen Rückgabewert 
liefern, selbst als Parameter übergeben zu können.
Was ich also zumindest schon mal ausklammern kann: ich will (vermutlich) 
keinen (vollwertigen) Compiler o.ä. basteln.
Von den verschiedenen Parsertypen, die ich bis jetzt gesehen habe, wäre 
es nach meinem Verständnis wohl am ehesten ein mathematischer Parser. 
Also "Kommandoformel" eintippen, Enter, fertig (oder Fehlermeldung 
grins ). Ist jetzt natürlich sehr vereinfacht ausgedrückt, das ist mir 
klar.

Laufen soll das Ganze auf einem Cortex-M0 bzw. M3 (bis 64kB RAM), 
programmiert wird in C.

Ich habe mir einige hier im Forum verfügbare Implementationen 
verschiedener Parser heruntergeladen und bin gerade dabei, die jeweilige 
Funktionsweise durchzugehen.
Das ist zwar hilfreich, um die grobe Funktionsweise an sich zu 
verstehen, aber ich bin jetzt an einem Punkt angekommen, an dem ich mich 
frage, ob ich den Lexer/Parser selber schreibe oder zu Tools wie 
Flex/Bison bzw. GOLD greife.
Selber schreiben würde natürlich die Details auftun und dem Verständnis 
sehr helfen. Die Verwendung von Tools ist gefühlt nicht unbedingt 
schneller, wenn ich davon ausgehe, dass es ein paar Anläufe braucht bis 
es korrekt beschrieben ist und funktioniert. Zumal es bei den Tools wohl 
so ist, dass generierte Ausgabe evtl. immer angepasst werden muss 
(Tabellen ins Flash, etc.).

Zu was würdet ihr tendieren, selber schreiben oder Parsergeneratoren 
verwenden? Und im Fall von selber schreiben, was nehmt ihr als Basis? Es 
gibt zig Webseiten, welche die Funktionsweise von Lexer/Parser recht 
gut, aber für mich abstrakt, erklären. Ich konnte mit meinen 
Suchbegriffen nichts finden, was ich als Grundlage verwenden konnte, um 
damit von Grund auf einen Parser zu schreiben.

Was brauche ich denn alles dazu?
* die Befehlszeile muss in Teilstrings zerlegt werden, Trenner sind ',' 
sowie Leerzeichen und Tabs (es sei denn, es kommt ein Paar 
Anführungszeichen vor)
* die Teilstrings werden typisiert, also in entsprechende 
Datentypen/Operatoren/Funktionsaufrufe konvertiert und/oder direkt als 
String/Bezeichner zusammen mit einem entsprechenden Tokenwert weiter 
gereicht
* Aus den Token wird der ParseTree aufgebaut und entsprechend 
abgearbeitet

Das Zerlegen, Konvertieren und die Werte mit Token zusammenführen traue 
ich mir noch zu (das dynamische Speicherhandling muss ich mir noch 
anschauen), aber das Erstellen und Abarbeiten vom ParseTree ist mir noch 
nicht klar.

Habt ihr Tipps für mich?

Ralf

von Dr. Sommer (Gast)


Lesenswert?

Hängt davon ab wie komplex die Sprache ist. Wenn es eine reguläre 
Sprache ist, reichen reguläre Ausdrücke und du kannst dir einen 
richtigen Parser sparen. Das sollte für die meisten einfachen 
Batch/Shell-Sprachen ausreichen.
Wenn du so etwas wie mathematische Formeln mit beliebiger 
Verschachtelung lesen können willst, brauchst du doch einen Parser. 
Schau dir auch mal Boost.Spirit an, damit brauchst du keinen Code zu 
generieren sondern kannst die Grammatik direkt im C++ Code definieren, 
aus welcher dann durch den C++ Compiler ein optimierter 
Parsing-Algorithmus generiert wird. Du musst dir halt überlegen, ob der 
Parserbaum (und der ganze Overhead für die Speicherverwaltung) in 64kB 
RAM passt...

von Zeno (Gast)


Lesenswert?

Was willst Du denn genau machen?

Ich bin gerade dabei eine Wetterstation zu bauen und da habe ich ein 
ähnlich gelagertes Problem.
Ich habe einen "Hauptrechner" der die Daten von mehreren Clients 
konsolidiert und weitere Berechnungen durchführt.

Die Clients sind untereinander und mit dem Hauptrechner per RS232, also 
seriell, verbunden. Alle Komponenten bilden also eine Kette 
(Hauptrechner <-> client1 <-> Client2 usw.)

Für Kommunikation habe ich mir folgenden Stringaufbau ausgedacht:
<Gerätegruppe>ID|Art|Param</Gerätegruppe>. Die gruppiert mehrere 
Clienten zu einer Gruppe. ID ist eine eindeutige ID für den jeweiligen 
Clienten innerhalb der Gruppe. Art gibt an ob Daten (D) oder Kommandos 
(C) übertragen werden. Param ist eine Parameterliste wobei die Parameter 
mit Semikola getrennt werden. Bei der Art Kommando (C) ist der erste 
Parameter das Kommando/der Befehl selbst. Ich habe mir eine kleine 
Routine geschrieben die diesen String auseinander fummelt. Der Client 
erkennt an Hand der Gruppe und der ID ob der Befehl für ihn selbst 
bestimmt ist, wenn nein wird der komplette String über den 2. UART an 
den nächsten Clienten durchgereicht. Letztendlich läuft das Ganze auf 
einen Parser hinaus. Die Kommandos auf die der Client reagiert sind in 
einer Liste hinterlegt.

Wenn ein Client eine Anforderung an den Hauptrechner sendet, dann 
bekommt dieser ebenfalls obigen String. Er erkennt welcher Client eine 
Anforderung gesendet hat und baut mit Daten (Gruppe und ID) einen 
Antwortstring.

Die Kommandos, die die Clienten verstehen sind können für jeden 
unterschiedlich sein.

Bei mir funktioniert das für den vorgesehenen Zweck ganz gut.

Vielleicht hilft es Dir ja etwas weiter. Das Ganze erhebt keinen 
Anspruch auf Perfektion . Kann man sicher auch anders lösen.

von Andreas R. (daybyter)


Lesenswert?

Evtl auch mal

http://www.antlr.org

anschauen.

von Detlev T. (detlevt)


Lesenswert?

Schon einmal an Forth gedacht?

von Wilko N. (woodi)


Lesenswert?

Moin,
für Befehle mit einfachen Argumenten hat sich bei mir folgendes bewährt, 
eine Art RPN-Konstrukt: Sendet man dem "Parser" einen String, sucht er 
in einer Liste nach bekannten Befehlen (zB set_samplingrate).
Wird kein bekannter Befehl gefunden, wird versucht, den string als Zahl 
zu interpretieren und die Zahl wird auf einen stack gepackt.
Ist der Befehl bekannt, wird dieser ausgeführt und kann auch Werte vom 
stack nehmen und auch Werte wieder auf diesen schieben.

Eine Konfig würde dann zB so aussehen:

1000
set_samplingrate
24
set_res
0
20
23
set_clock


Nicht sehr elegant, kein richtiger Parser, aber fix programmiert und 
erfüllt seinen Zweck (bei mir^^).
Ist natürlich dann auch nicht in der art samplingrate=1000...

Viele Grüße

Wilko

: Bearbeitet durch User
von Possetitjel (Gast)


Lesenswert?

Ralf schrieb:

> Selber schreiben würde natürlich die Details auftun
> und dem Verständnis sehr helfen. Die Verwendung von
> Tools ist gefühlt nicht unbedingt schneller, wenn ich
> davon ausgehe, dass es ein paar Anläufe braucht bis
> es korrekt beschrieben ist und funktioniert. Zumal es
> bei den Tools wohl so ist, dass generierte Ausgabe evtl.
> immer angepasst werden muss (Tabellen ins Flash, etc.).
>
> Zu was würdet ihr tendieren, selber schreiben oder
> Parsergeneratoren verwenden? Und im Fall von selber
> schreiben, was nehmt ihr als Basis?

Man kann mit endlichen Automaten ("finite state machines")
recht weit kommen. Voraussetzung ist natürlich, dass man
die Grundbegriffe zuverlässig beherrscht (Festlegen der
Zustände; Überführungsfunktion; Ausgabefunktion) und eine
gewisse Systematik hat, wie man das aufschreibt. Kenntnisse
der Steuerungstechnik sind hilfreich.

Je nach Problem kann auch die umgekehrte polnische Notation
ein Geheimtipp sein; der zugehörige Kellerautomat ist noch
ziemlich einfach, aber schon ziemlich leistungsfähig.

von Keller (Gast)


Lesenswert?

Wilko N. schrieb:
> ine Art RPN-Konstrukt: Sendet man dem "Parser" einen String, sucht er
> in einer Liste nach bekannten Befehlen (zB set_samplingrate).
> Wird kein bekannter Befehl gefunden, wird versucht, den string als Zahl
> zu interpretieren und die Zahl wird auf einen stack gepackt.
> Ist der Befehl bekannt, wird dieser ausgeführt und kann auch Werte vom
> stack nehmen und auch Werte wieder auf diesen schieben.

Client stürzt ab und es liegen noch Werte auf dem Stack, was passiert 
mit den Werten auf dem Stack?

von Dumdi D. (dumdidum)


Lesenswert?

Wenn ich Dein Problem richtig verstanden habe, ist TCL fuer dieses 
Problem gemacht. Du kannst es in C einbetten, und eigene Kommandos 
definieren. Nur mal so.als.Alternativvorschlag.

von Hannes J. (Firma: _⌨_) (pnuebergang)


Lesenswert?

Ralf schrieb:
> Je mehr ich nun versuche, in die Thematik zu kommen, desto verwirrender
> wird's momentan: suche ich nun einen Interpreter, einen Parser, eine
> Commandshell oder einen Mix aus allem?

Die meisten einfachen Commandshells sind als Interpreter realisiert. Es 
gibt allerdings kein Gesetz, dass das vorschreibt.

Ein Parser bereitet Eingangsdaten so auf, dass man deren Bedeutung 
analysieren kann. Sowohl Compiler als auch Interpreter verwenden daher 
Parser. Bei einfachen Sprachen geht der Parser im Code schon mal unter, 
weil er ad-hock im Code eines Interpreters (seltener eines Compilers) 
zusammengeschustert wurde.

Mixe von Compiler und Interpreter gibt es schon lange. Traditionell wird 
dabei in einen Zwischencode (statt Maschinencode) compiliert, der zur 
Laufzeit interpretiert wird. In neuerer Zeit compiliert man den 
Zwischencode teilweise zur Laufzeit nach (Hotspot Compiler).

Die älteste für Embedded genutzte Sprache, die ein Mix ist, dürfte FORTH 
sein. Forth kommt mit einem eingebauten Kommandozeilen-Interpreter, 
einem Compiler, und einem weiteren Interpreter[1] für den kompilierten 
Zwischencode. Das ganze passt trotzdem noch in ein paar Kilobyte.

Eine andere Sprache, die typischerweise als Mix aus Kommandozeile und 
Programmierumgebung kommt und traditionell als Interpreter, ist BASIC. 
Auch hier passen klassische Implementierungen in ein paar Kilobyte[2]. 
Beispiel https://en.wikipedia.org/wiki/Tiny_BASIC

Nicht zu vergessen die original v7 Bourne-Shell ist vom Code auch 
ziemlich klein. Allerdings verwendet sie viele Betriebssystemfunktionen, 
die dir fehlen dürften.

> Von der Art her hätte ich's gern ála Kommandokonsole.

Nur die Kommandozeile, oder auch (wie bei FORTH, BASIC, sh)  die 
Möglichkeit kleine Programme zu erstellen?

> vorschwebt, wäre z.B. Unterstützung von Umgebungsvariablen, die man auch
> als Parameter an Kommandos weitergeben kann, und die Möglichkeit,
> Befehle bzw. mathematische Ausdrücke/Formeln, die einen Rückgabewert
> liefern, selbst als Parameter übergeben zu können.

Wenn du die Formeln in bekannter Notation schreiben möchtest, dann eher 
einen BASICaritigen Interpreter. Wenn RPN ok ist, dann FORTH.

> Von den verschiedenen Parsertypen, die ich bis jetzt gesehen habe, wäre
> es nach meinem Verständnis wohl am ehesten ein mathematischer Parser.

Der dir alleine nichts nützt. Du brauchst einen 
Kommandozeilen-Interpreter, der natürlich intern einen Parser verwendet.

Bei einem Mathe-Parser fehlt der Interpreter und was willst du mit 
etwas, dass einzig und alleine Formeln zur weiteren Bedeutungsanalyse 
auswertet?

> Ich habe mir einige hier im Forum verfügbare Implementationen
> verschiedener Parser heruntergeladen

Ein Parser alleine hilft nicht. Ich hoffe mal, dass ein paar davon 
Interpreter waren, die nur jemand Parser genannt hat.

> aber ich bin jetzt an einem Punkt angekommen, an dem ich mich
> frage, ob ich den Lexer/Parser selber schreibe oder zu Tools wie
> Flex/Bison bzw. GOLD greife.

Wenn du eine fertige Sprache oder einen fertigen Interpreter nimmst, 
dann hat dir jemand sowohl diese Entscheidung, als auch die 
Implementierung des Parsers abgenommen.

> Zu was würdet ihr tendieren, selber schreiben oder Parsergeneratoren
> verwenden?

Bei kleinen Aufgaben Interpreter mit Parser von Hand schreiben

Bei großen Aufgaben fertige Sprache nehmen.

Parsergenerator nur wenn es um eine große, spezielle Aufgaben geht, für 
die es nichts gibt. Für die Auswertung von Kommandozeilen gibt es mehr 
als genug.

> Ich konnte mit meinen
> Suchbegriffen nichts finden, was ich als Grundlage verwenden konnte, um
> damit von Grund auf einen Parser zu schreiben.

Dragon Book oder Drachenbuch googlen.

> aber das Erstellen und Abarbeiten vom ParseTree ist mir noch
> nicht klar.

Das ist der Kern des Interpreters oder Compilers.

> Habt ihr Tipps für mich?

Dragon Book / Drachenbuch oder eine fertige Sprache nehmen.

-----
[1] Beide Interpreter teilen sich den selben Code, der zweite kostet 
praktisch nichts extra.

[2] Schon frühe BASIC-Interpreter hatten als Optimierung gelegentlich 
eine kleine Compiler-Komponente. Die Zeilennummer von Sprungzielen wurde 
in eine Speicheradresse übersetzt. Damit sparte man sich das elendig 
langsame lineare Suchen nach der Sprungziel-Zeilennummer bei jedem 
Sprung.

von MikeH (Gast)


Lesenswert?

Ralf schrieb:
> Befehle an einen µC zu
> senden. Im kleinen Rahmen konnte ich mir bisher immer damit behelfen,
> einzelnen Zeichen bestimmte Funktionen zuzuordnen. Das aktuelle Projekt
> ist ein bisschen größe

Die Tipps für parsen und interpretieren hier sind schön und gut aber 
denk mal nach ob es wirklich die richtige Lösung ist.

Eine µC seitige API ist imho die beste Lösung und auch für sehr große 
Anwendungen geeignet.
In C kannst du für jeden Befehl eine struct mit den Parametern bauen. 
Über deine Verbindung (RS232, RS485, USB, TCP/IP, ...) schickst du dann 
[START, FUNKTIONSID, LÄNGE, PAYLOADSTRUCT, ... PRÜFSUMME, STOP]. Im µC 
reicht dann ein einfaches switch(FUNKTIONSID) {...} et voila.

Das hat mMn gleich mehrere Vorteile:
* auf PC Seite kannst du eine graphische Oberfläche oder einen einfachen 
Kommandointerpreter bauen. (z.B. mit QT oder TCL/TK sogar portabel für 
gängige OS)
* bei der Übertragungsschicht bist du flexibel (s.o)
* auf µC Seite sparst du dir das rumgefrickel mit Strings, parsen etc.

Wenn du keine "Programme" zum interpretieren an den µC  senden musst, 
ist diese Lösung besonders für große Projekte aus meiner Sicht 
wesentlich sauberer und auch flexibler.

Gruß Mike

von Ralf (Gast)


Lesenswert?

Hallo zusammen,

vielen Dank für die zahlreichen Antworten.

@Dr.Sommer:
> Du musst dir halt überlegen, ob der Parserbaum (und der ganze Overhead für > die 
Speicherverwaltung) in 64kB RAM passt...
Kann das wirklich wirklich 64kB sprengen? Mir ist bewusst, dass es mit 
ein paar Bytes RAM nicht getan ist, aber das so etwas tatsächlich an die 
64 kB oder darüber kommen kann, hätte ich nicht gedacht.

@Zeno:
> Was willst Du denn genau machen?
Danke für die Erläuterungen zu deiner Wetterstation. Später möchte ich 
auch mal etwas mit mehreren Teilnehmern an einem Bus machen, da eignet 
sich der (relativ) fixe Aufbau wie es dein Protokoll macht 
wahrscheinlich eher.
In meinem konkreten Fall möchte ich (erstmal) bspw. Parameter zur 
Laufzeit ändern/abfragen, Ein-/Ausgänge lesen/setzen und ggf. die eine 
oder andere Funktion aufrufen. Also erstmal unterste Steuerungsaufgaben.

@Andreas Rückert:
Danke, schau ich mir an.

@ Detlev T.:
Schaue ich mir ebenfalls an.

@Wilko:
Mjaaaa, das geht ungefähr in meine Wunschrichtung, wobei ich schon gern 
wie du auch geschrieben hast, die Zuweisung mit '=' und den 
Funktionsaufruf wahlweise mit Klammernpaaren und Parameter getrennt 
durch Komma sowie ohne Klammernpaar und Komma hätte - in dem Fall evtl. 
benannte Parameter, damit die Reihenfolge keine Rolle spielt.
Wobei das jetzt schon wieder arg oversized klingt. Das ging mir halt 
anfangs so durch den Kopf.

@Possetitjel:
Das steht auch auf der Liste. Intern in UPN umzubauen sollte auch gehen.

@Dumdi Dum:
Okay, dann werde ich mir TCL auch ansehen =)

@Hannes Jaeger:
Vielen Dank für die ausführlichen Erläuterungen.

>> Von der Art her hätte ich's gern ála Kommandokonsole.
> Nur die Kommandozeile, oder auch (wie bei FORTH, BASIC, sh)  die
> Möglichkeit kleine Programme zu erstellen?
Naja, wenn FORTH insgesamt nicht wirklich groß (relativ zu anderen 
Interpretern/Parsern) ist, könnte es auch die "Vollversion" sein. Ich 
kann mich ja trotzdem erstmal auf die Eingabe einzelner Zeilen 
beschränken.

> Der dir alleine nichts nützt. Du brauchst einen Kommandozeilen-
> Interpreter, der natürlich intern einen Parser verwendet.
> Bei einem Mathe-Parser fehlt der Interpreter und was willst du mit
> etwas, dass einzig und alleine Formeln zur weiteren Bedeutungsanalyse
> auswertet?
> Ein Parser alleine hilft nicht. Ich hoffe mal, dass ein paar davon
> Interpreter waren, die nur jemand Parser genannt hat.
Genau deswegen habe ich eingangs geschrieben, dass ich nicht alle 
Begrifflichkeiten für ein und dasselbe halte ;)

>> Ich konnte mit meinen Suchbegriffen nichts finden, was ich als Grundlage
>> verwenden konnte, um damit von Grund auf einen Parser zu schreiben.
> Dragon Book oder Drachenbuch googlen.
Danke, werd ich machen.

@MikeH:
Danke für die Idee. Ich sehe die Vorteile, aber der Nachteil ist m.E. 
dass man auf der Gegenseite die Befehle "generieren" muss. Das wollte 
ich eigentlich vermeiden, an zwei Ecken zu programmieren. Ich muss mir 
das nochmal durch den Kopf gehen lassen, ob das nicht doch evtl. die 
bessere Wahl ist.

Ralf

von Markus (Gast)


Lesenswert?


von Dr. Sommer (Gast)


Lesenswert?

Ralf schrieb:
> Kann das wirklich wirklich 64kB sprengen?

Das hängt von der Größe der Eingabe ab! Ein Quellcode mit tausenden 
Zeilen wird da wohl nicht reinpassen, eine einzelne Befehlszeile mit 
Max. 100 Syntax Elementen schon eher. Es wäre dabei schlau beim parsen 
auf "out of memory " zu prüfen und dann sauber abzubrechen anstatt 
abzustürzen ;-)

Schau vielleicht auch mal nach eLua das ist für sowas gemacht.

Ich finde es auf jeden Fall spannend so etwas selber zu implementieren 
auch wenn das länger als nötig dauert, du musst selbst wissen wie viel 
du selber machen willst. Man kann ja auch seinen eigenen Parser bauen, 
dem man Grammatik + Eingabetext  gibt und der den Syntax Baum 
zurückgibt, ggf direkt ohne einen Parser-Code (in C) zu generieren. Die 
Grundversion ist relativ simpel, aber das effizient und flexibel 
hinzubekommen ist nicht so einfach ;-)

von Johannes S. (Gast)


Lesenswert?

wie wäre es mit JSON? Es gibt einen sehr kompakten parser, JSMN : 
http://zserge.com/jsmn.html
Ist zwar kein richtiger Kommonadozeileninterpreter, aber das lässt sich 
dann gut durch ein Programm bedienen.

von Brummbär (Gast)


Lesenswert?

Ralf schrieb:
> In meinem konkreten Fall möchte ich (erstmal) bspw. Parameter zur
> Laufzeit ändern/abfragen, Ein-/Ausgänge lesen/setzen und ggf. die eine
> oder andere Funktion aufrufen. Also erstmal unterste Steuerungsaufgaben.

Hier reicht es doch aus, dass ein festes Protokoll verwendet wird.
Beispielsweise ein Befehlswort aus einem oder mehreren Zeichen, gefolgt 
von irgendwie getrennten Daten. Die Daten könnten auch binär übertragen 
werden. Das macht es zwar einem Menschen schwerer, per Terminal 
zuzugreifen, ist aber einfacher zu parsen (zB. Zahleneingaben).

Beispie:
1
D:100          Setze Verzögerung auf 100.
2
D              Liefert die aktuell eingestellte Verzögerung zurück.
3
X:2,3,4        Befehl mit mehreren Parametern.

Hierzu ist kein flexibler Parser notwendig. Es müssen lediglich die 
Parameter aufgeschlüsselt werden. Ist jeweils nur maximal ein Parameter 
erlaubt, macht es die Sache noch einfacher.

von Martin S. (strubi)


Lesenswert?

Bison, JSON, Boost, TCL...und das auf einem uC? Im Ernst, Leute? Ich 
schmeiss gleich noch .NET in die Runde.

Mein Credo, keep it simple. Eine shell, die keine mathematischen 
Ausdrücke auflösen muss, braucht keinen dicken Parser, es reicht eine 
einfache State-Machine mit weniger Zeilen, als ihr euch hier schon einen 
Wolf geschrieben habt.
Als Anschauungsbeispiel (wenn zu primitiv, darf es gerne aufgebohrt 
werden): http://section5.ch/dsp/blackfin/shell-1.1eval.tgz, siehe 
shell.c
Wenn die Shell zum KOnfigurieren/Abfragen von Werten im Klartext dienen 
soll: Die guten alten AT-Modem-Kommandokonzepte sind zwar grottig, aber 
nicht totzukriegen. Einfacher ist nur noch eine simple 
register-orientierte API.

von Axel S. (a-za-z0-9)


Lesenswert?

Ralf schrieb:
> In meinem konkreten Fall möchte ich (erstmal) bspw. Parameter zur
> Laufzeit ändern/abfragen, Ein-/Ausgänge lesen/setzen und ggf. die eine
> oder andere Funktion aufrufen. Also erstmal unterste Steuerungsaufgaben.

Dann reicht ein relativ simpler Parser, den du z.B. mit bison generieren 
lassen kannst. In das action-Feld jeder Parser-Regel packst du einfach 
Aufrufe der Funktionen, die die gewünschte Operation ausführen. Du 
ersetzt einfach deine bisherige switch () case Orgie durch den Parser.

Ob du für den Lexer auf z.B. flex zurückgreifen mußt oder den von Hand 
schreiben willst, kommt auf die Komplexität deiner "Sprache" an.

von (º°)·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.·´¯`·.¸¸.· (Gast)


Lesenswert?

Die "Klassiker" der einfachen Kommandointerpreter nehmen einfach
die ersten N (z.B. 4) Zeichen und interpretieren sie als Zahl die dann
einfach in einem Switch landet. Siehe z.B. die ganzen ftpd.
Abkuerzungen waeren dann nur ein weiterer case in diesem Switch.
Fuer Trennzeichen, Zahlen und Stringargumente braeuchte Mann dann
noch weitere Funktionen die Pattern Matching und Evaluierung betreiben.

Ob sich fuer sowas ein *lex" lohnt?

Sowas wie:

> 1000
> set_samplingrate
> 24
> set_res
> 0
> 20
> 23
> set_clock

koennte auch ein Forthinterpreter relativ direkt verwursten.

von Zeno (Gast)


Lesenswert?

Ralf schrieb:
> In meinem konkreten Fall möchte ich (erstmal) bspw. Parameter zur
> Laufzeit ändern/abfragen, Ein-/Ausgänge lesen/setzen und ggf. die eine
> oder andere Funktion aufrufen. Also erstmal unterste Steuerungsaufgaben.

Das würde mit meinem Konstrukt schon gehen. Bei meiner Lösung würde ich 
im Parameterblock z.B. Folgendes schreiben:
setPort;4;5;OUTPUT;1  >> übersetzt: setze Port 4.5 als Ausgang und auf 
HIGH. Du müßtest also dem Befehl "setPort" nur eine passende Funktion 
zuordnen und dieser die restlichen Parameter übergeben. Den Rest von 
meinem Ausgangskonstrukt kann man ja erst mal weglassen, wenn man keinen 
Bus aufbauen will.

von Olaf (Gast)


Lesenswert?

> Habt ihr Tipps für mich?

Nimm Flex. Ich hab es schon genau fuer das was du da machen willst 
verwendet. Im Prinzip brauchst du hoechstens 1-2h um dir das Inputscript 
fuer flex zu schreiben das dir den C-Source erzeugt welche dann deine 
Funktionen mit den richtigen Parametern aufrufen. Beim erstenmal 
brauchst du vermutlich 3h laenger um die Manpage zu lesen oder etwas zu 
lernen.

Der Vorteil von flex kommt danach. Wann immer du deinen Interpreter 
spaeter um ein neues Kommando oder ein vorhandenes Kommando um einen 
Parameter erweitern willst dann ist das in 1min zu loesen.

Ich hab ausserdem noch ein kleines Programm im Sourcetree welches eines 
Testumgebung fuer mein Betriebssystem erzeugt. Damit kann ich 
Aenderungen am Flexinterpreter auf dem PC testen bevor es in den 
Microcontroller geht.

Wie schon gesagt, die Nutzung ist eine wahre Freude! Und weil es so 
schoen schnell und einfach geht neigt man dazu jede Menge kleine Befehle 
in seinen Interpreter einzubauen um die Funktionalitaet des eigenen 
Programmes und seiner Hardware sehr gut testen zu koennen. Dadurch 
steigt die Codestabilitaet immens an. Bei mir laeuft das fertige 
Programm dann auf einem ST32F103.

Olaf

von Gerhard O. (gerhard_)


Lesenswert?

Vor acht Jahren hatte ich die Gelegenheit eine Zeitlang in der Arbeit 
mit einem FORTH System zu spielen welches auf einer Embedded Artist Dev 
Board lief mit LPC2467 Prozessor drauf und TFT LCD und in C geschrieben 
war. Es war sehr leicht neue Keywords ins Dictionary hinzuzufügen und 
man konnte alles von der command line aus machen. Auch als RPN 
Calculator konnte man es verwenden. Hat mächtig Spaß gemacht damit zu 
arbeiten. Neue Commands konnten praktisch in Minuten geschrieben und 
compiliert werden. Compiler war von IAR. Es war ein sehr beeindruckendes 
System. Ein Bekannter von mir schrieb das Ganze von Start an. Sogar 
320x240 TFT Graphikfunktionion hatten wir laufen. Für das Testen von 
Hardware war FORTH ideal. Leider habe ich nicht mehr die Sourcen dafür. 
Aber es war eine gute Lern Experience.

Eigentlich sollte man auch heutzutage noch FORTH nicht übersehen. Es 
könnte für bestimmte Sachen immer noch ganz nützlich sein. Früher hatte 
man damit angeblich sogar große Teleskope gesteuert.

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

Ich hab mir in solchen Situationen immer meinen Parser mit strtok(), 
atoi(), strtol() und so weiter selbst zusammengeschustert. Erstes Wort 
ist der Befehl, dann kommen die Argumente, reicht aus.

Die Hauptschleife testet die wichtigsten Befehle ("quit", "help") direkt 
ab, wandert dann durch eine Tabelle { "befehl", "beschreibung", 
funktionspointer }[NUM_COMMANDS] und ruft die entsprechende Funktion mit 
dem Reststring auf. Diese Funktionen parsen ihre Argumente selbst und 
geben einen Fehlercode zurück.

Reicht völlig hin, ist mit 20 Zeilen Code erledigt, und bis auf fehlende 
History und mangelhaften Zeileneditor (nur Backspace) auch relativ 
bequem.

Wichtig ist, dass eine überlange Zeile keinen Überlauf produziert.

von Pandur S. (jetztnicht)


Lesenswert?

Falls moeglich sollte man das Protokoll zustandsfrei schreiben. Denn was 
geschieht, wenn ein Befehl unterwegs verloren geht ? Er wird wiederholt, 
wie selten auch immer das geschieht. Es geschieht ...

zB
 SetAusgang=high : wiederholung ist ok
 ToggleAusgang   : wiederholung ist wahrscheinlich nicht ok
 IncrementPower  : wiederholung ist nicht ok
 Power=200       : wiederholung ist ok
 Datenblock(200) : wiederholung ist ok
 NextDatenblock  : wiederholung ist nicht ok

Alles klar ?

von Strubi (Gast)


Lesenswert?

Forth ist mal gar nicht so exotisch wie's klingt, wer kennt nicht Chuck 
Moores Forth Prozessoren (HW). Die J1 und andere Derivate sind mal 
richtig cool. Irgendwer hat halt mal Stackmaschinen als uncoole Hardware 
definiert, so existieren sie vor allem in Software. Für einen Parser 
dürfte bei einer SM allerdings der kompakteste Code bei rausschauen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ralf schrieb:
> Tools wie Flex/Bison

Wenn, dann würde ich eher zu byacc als bison tendieren, schon der
embedded-freundlicheren Lizenz wegen.

Ich habe vor Jahren mal (aus Spaß) einen BASIC-Interpreter für einen
ATmega128 mit flex/byacc geschrieben.  War nicht ganz leichtgewichtig,
funktionierte aber durchaus brauchbar.  Sollte also auf einem M0 kein
Problem sein.

Du schleppst zwar bisschen mehr Overhead als bei einer handgefeilten
Lösung mit, aber dafür kannst du das Ding einfach als Werkzeug benutzen
und dich auf dein eigentliches Problem konzentrieren.

von Marian M. (mrhat2010)


Lesenswert?

Also laut Wikipedia steht der erzeugte Code von Bison nicht zwangsläufig 
unter der GPL, dies war aber in älteren Versionen wohl anders...
https://en.wikipedia.org/wiki/GNU_bison#Licence_and_distribution_of_generated_code

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Möglich.  Bison ist aber ohnehin m. W. aufgeblasener als byacc, schon
deshalb wäre es für einen schmalbrüstigen Controller nicht meine Wahl
gewesen.

(Natürlich musste ich, damit das auf einem AVR sinnvoll funktioniert,
sowohl byacc als auch flex patchen, damit sie Flash-Konstanten für die
vielen Tabellen erzeugen. Für den hier gewünschten Cortex-M sollte es
aber aus der Dose raus mit beiden funktionieren.)

von Dr. Sommer (Gast)


Lesenswert?

Olaf schrieb:
> Der Vorteil von flex kommt danach. Wann immer du deinen Interpreter
> spaeter um ein neues Kommando oder ein vorhandenes Kommando um einen
> Parameter erweitern willst dann ist das in 1min zu loesen.

In Boost.Spirit geht das sogar noch schneller - man passt die 
Grammatikdefinition direkt im C++ Code an, und ruft den C++ Compiler neu 
auf. Man braucht keine externen Tools und man kann problemlos beliebig 
viele verschiedene Sprachen parsen ohne am Buildsystem rumbasteln zu 
müssen. Einfache Sprachen (z.B. reguläre) kann man in 1 Zeile parsen 
(inkl. Definition!).
Das ist das Schöne an einer Lösung, die auf Metaprogrammierung basiert.

Ein sehr einfaches Beispiel findet sich hier:
Beitrag "Re: Datenreihe neu Sortieren"
Alles ist kompakt in einer kleinen Sourcedatei, es musst nur eben Boost 
installiert sein.

Was man prüfen müsste ist ob man dessen dynamische Speicherallokation 
genug reduzieren kann damit es auf Mikrocontroller passt.

von Markus F. (mfro)


Lesenswert?

Dr. Sommer schrieb:
> Alles ist kompakt in einer kleinen Sourcedatei, es musst nur eben Boost
> installiert sein.
>
> Was man prüfen müsste ist ob man dessen dynamische Speicherallokation
> genug reduzieren kann damit es auf Mikrocontroller passt.

Was höchstwahrscheinlich bedeutet, dass man ein simples Problem 
erfolgreich durch ein höchst komplexes ersetzt hat ;)

von Olaf (Gast)


Lesenswert?

> In Boost.Spirit geht das sogar noch schneller - man passt die
> Grammatikdefinition direkt im C++ Code an, und ruft den C++ Compiler neu
> auf.

Wieso sollte das jemand interessieren? Auf Mikrocontrollern wird zu 99% 
C verwendet und flex liefert reinen C-Code der ohne Aenderung direkt 
fuer einen Microcontroller compiliert und verwendbar ist. Auch flex ist 
schon etwas Resourcenverschwendend was Flashverbrauch angeht, aber da 
man ja heute praktisch immer 64-128k oder mehr hat ist das nicht mehr so 
das Problem.

Olaf

von Dr. Sommer (Gast)


Lesenswert?

Olaf schrieb:
> Auf Mikrocontrollern wird zu 99% C verwendet
Interessante Aussage, wo ist deine Quelle? Das hat mich schon immer 
interessiert. Viele behaupten, es sind 50% Matlab.

Jedenfalls kann man erwiesenermaßen sehr gut C++ auf Mikrocontrollern 
nutzen, und es bei Bedarf auch mischen. C++ Code kompiliert auch auf 
Mikrocontrollern ohne Änderung, man muss nur an den entscheidenden 
Stellen  die richtigen Container-Typen & Allokatoren auswählen. Daher 
finde ich es durchaus interessant. Habe aber gerade keine Zeit es selbst 
vernünftig auszuprobieren.

von Olaf (Gast)


Lesenswert?

> Interessante Aussage, wo ist deine Quelle?

Mein Bauch.

> Viele behaupten, es sind 50% Matlab.

Nur bei den Ruebennasen frisch von der Uni. In der Praxis lernen die 
dann entweder was richtiges oder machen auf Projektleiterassistent. :-)

> Jedenfalls kann man erwiesenermaßen sehr gut C++ auf Mikrocontrollern
> nutzen, und es bei Bedarf auch mischen.

Theoretisch, aber die Schnittmenge aus guten Embeddedprogrammierern und 
guten C++ Programmierern ist zu klein. Daher noch keine praxisrelevanz.
Ausserdem hat der OP gleich im ersten Posting zu erkennen gegeben das er 
in C programmiert.

> Habe aber gerade keine Zeit es selbst vernünftig auszuprobieren.

Du bist faul und willst anderen deine Traeume aufzwingen?

Olaf

von Dr. Sommer (Gast)


Lesenswert?

Olaf schrieb:
> Mein Bauch.
Ah, die gekonnte Argumentationsart sich Zahlen auszudenken wie sie einem 
passen.

Olaf schrieb:
> Theoretisch, aber die Schnittmenge aus guten Embeddedprogrammierern und
> guten C++ Programmierern ist zu klein.
Ich würde fast behaupten, dass gute Embedded Programmierer keine 
größeren Probleme mit C++ haben sollten.

Olaf schrieb:
> Daher noch keine praxisrelevanz.
C++ gibts ja erst seit 30 Jahren, dauert noch ein paar bis es von der 
Industrie angenommen wird? Klingt eher nach Unwillen (was der Bauer 
nicht kennt, ...).

Olaf schrieb:
> Du bist faul und willst anderen deine Traeume aufzwingen?
Ich wollte lediglich auf eine Möglichkeit hinweisen. Der OP darf ja auch 
selbst etwas tun. Du hast mit rumstänkern angefangen.

von lazycoder (Gast)


Lesenswert?

> Habt ihr Tipps für mich?


Ev. http://bitlash.net/ ?

von Ralf (Gast)


Lesenswert?

Hallo,

sorry für die späte Rückmeldung, vielen Dank für eure weiteren Beiträge.
Da ist ja ganz schön was zusammen gekommen =)

@Dr.Sommer:
Japp, sind ja jeweils nur einzelne Zeilen. Und out-of-memory versuche 
ich natürlich im Auge zu behalten. Bin auch grad am schauen, ob man 
Infos zum Heap oder "unbereinigte" malloc()-Aufrufe erkennen/abfragen 
kann.
eLua geht nicht, das sprengt Flash & RAM, wenn ich die Infos auf der 
eLua-Seite so anschaue.

@Johannes:
JSON schau ich mir an, danke.

@Brummbär:
Ja, für das aktuelle Projekt würde das wahrscheinlich auch reichen. 
Parsen, Kommandozeile, etc. ist halt immer interessanter geworden, je 
mehr ich mich damit beschäftigt habe =)

@Martin S.:
grins .NET geht leider auch nicht auf dem System (aber jucken würd's 
mich schon, das mal auf einem µC zu probieren). Aber ich glaub da war 
auch noch was mit Lizenzen, etc.
Das Beispiel schau ich mir an, danke.

@Axel:
Für lex & yacc hab ich mir ein Buch vom Kollegen geliehen, werd ich auch 
anlesen.

@(º°):
Stimmt, auch eine KISS-Variante.

@Zeno:
Das geht schon in die (meine) richtige Richtung.

@Olaf:
Hört sich gut an. Werd mich dazu durch das o.e. Buch lesen.

@Gerhard:
Hab ein bisschen bzgl. FORTH nachgeschaut, scheint wirklich für den 
Einsatz auf µCs gemacht zu sein (zumindest laut Wiki).

@S.R.:
Das war auch was, was mir durch den Kopf ging. Aber ist es nicht 
umständlich, wenn die Funktionen selbst parsen müssen? Das bläht doch 
immens auf, oder?

@Sapperlot W:
Ähm... nein, nicht ganz klar =) Was heisst zustandsfrei? Wenn ein Befehl 
nicht korrekt empfangen wird, dann muss erkannt werden, dass ein neuer 
Befehl beginnt anstatt diesen als Teil des "kaputten" Befehls zu 
erkennen?

@Strubi:
Du meinst, weil in FORTH die Eingabe gleichzeitig der Befehl selbst ist?

@Jörg:
Wie bereits erwähnt, sobald ich verstanden habe, wie 
Bison/YACC/BIYACC/FLEX/LEX etc. genau funktionieren, werde ich das mal 
anprobieren.

@lazycoder:
Bitlash muss doch in Verbindung mit der Arduino-Umgebung laufen, oder?

Bei den restlichen Beiträgen ging es nicht konkret um mein Thema, daher 
antworte ich darauf nicht. Trotzdem interessant zu lesen ;)

Nochmals danke an alle für die zahlreichen Antworten.

Ralf

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ralf schrieb:
> Hab ein bisschen bzgl. FORTH nachgeschaut, scheint wirklich für den
> Einsatz auf µCs gemacht zu sein

Sagen wir mal so: als es erfunden wurden ist, gab es noch gar keine
Mikrocontroller oder man hat sie zumindest noch nicht so genannt. :)

Aber für Mikrocomputer ist es in der Tat ausgelegt worden.

von Olaf (Gast)


Lesenswert?

> Sagen wir mal so: als es erfunden wurden ist, gab es noch gar keine
> Mikrocontroller oder man hat sie zumindest noch nicht so genannt. :)

Forth war interessant als es noch nicht heutige Entwicklungssysteme gab. 
Als man also ein EPROM und etwas RAM am Microcontroller hatte und die 
Alternative aus EPROM loeschen/brennen bestand. Ich hab mich damals ja 
auch dafuer interessiert und st6forth geschrieben. Allerdings schon kein 
klassisches Forth sondern ein Compiler.
Interessant waren die echten Forthinterpreter damals weil man in 
Echtzeit entwickeln konnte. Allerdings heute mit den Moeglichkeiten 
eines Debuggers und der Programmierschnittstelle auf der Zielhardware 
sehe ich keine grosse Relevanz mehr. Die Vorteile sind gering geworden, 
wenn zum Teil auch noch vorhanden. Dafuer sind aber die Nachteile extrem 
gewachsen. Ein Forth-programm ist nicht gerade ein Muster an 
selbsterklaerendem. Wenn man bedenkt was heutige Microcontroller an 
Platz bieten und das es Programme gibt die den auch nutzen dann kommt 
man sehr schnell an Grenzen wo man nicht mehr versteht was man selber 
geschrieben hat. Und diese Grenze ueberschreitet man deutlich schneller 
als bei C.

Die Sprache ist aber natuerlich ein schoenes intellektuelles Spielzeug. 
So gesehen kann sich die Beschaeftigung doch wieder lohnen. :-)

Olaf

von Dumdi D. (dumdidum)


Lesenswert?

Dr. Sommer schrieb:
> C++ gibts ja erst seit 30 Jahren, dauert noch ein paar bis es von der
> Industrie angenommen wird?

Das ist doch kein Argument. Lisp gibt es seit 60 Jahren und es ist noch 
nicht auf muc angekommen. Das Problem ist, das C++ fuer Systeme mit 
Beschraenkungen bei der dynamischen Speicherverwaltung nur 
eingeschraenkt verwendbar ist und seine Staerken nicht ausspielen kann.

von Peter (Gast)


Lesenswert?

Mit dem innovativen Entwicklungssystem "Arduino" ist C++ aber schon seit 
10 Jahren millionenfach auf dem Mikrocontroller angekommen.
Nur bei manchem MC-Netz Nutzer geht's halt ein wenig länger.

von Dr. Sommer (Gast)


Lesenswert?

Dumdi D. schrieb:
> Das Problem ist, das C++ fuer Systeme mit Beschraenkungen bei der
> dynamischen Speicherverwaltung nur eingeschraenkt verwendbar ist und
> seine Staerken nicht ausspielen kann.

C++ hat noch viel mehr Stärken außer ein paar Containern in der Standard 
Library, welche dynamische Speicherverwaltung brauchen. Das geht von 
sowas einfachem wir Funktions Overloads bis zu Metaprogrammierung. Und 
das kann man sehr wohl sinnvoll auf Mikrocontrollern nutzen. Der 
Hauptgrund warum C da noch so dominant ist, ist wahrscheinlich dass 
Embedded Entwicklung oft von E-Technikern gemacht wird und die nur C in 
Studium lernen. Im Informatik Studium hatten wir jedenfalls "Embedded 
C++".

von Simon K. (simon) Benutzerseite


Lesenswert?

Als konkretes Beispiel hier das Chameleon-Mini, was ich damals bei 
Kasper und Oswald entwickelt habe. Da gibt es eine einfache 
Kommandozeile.
https://github.com/emsec/ChameleonMini/tree/master/Firmware/Chameleon-Mini/Terminal

von Nop (Gast)


Lesenswert?

Man kann sich natürlich auch einfach einen Tokenizer schreiben (oder 
strtok nehmen) und dann mit einem endlichen Automaten arbeiten. So habe 
ich schon AT-Parser geschrieben, als man µCs noch mit Dampf betrieben 
hat.

von Carl D. (jcw2)


Lesenswert?

Dr. Sommer schrieb:
> Dumdi D. schrieb:
>> Das Problem ist, das C++ fuer Systeme mit Beschraenkungen bei der
>> dynamischen Speicherverwaltung nur eingeschraenkt verwendbar ist und
>> seine Staerken nicht ausspielen kann.
...
> Der Hauptgrund warum C da noch so dominant ist, ist wahrscheinlich dass
> Embedded Entwicklung oft von E-Technikern gemacht wird und die nur C in
> Studium lernen. Im Informatik Studium hatten wir jedenfalls "Embedded
> C++".

Wobei man auch berücksichtigen muß, daß vieles außer den "bösen 
Containern" erst mit C++11 dazu kam und viele im Embeded-Bereich 
kommerziell genutzte Toolchains schon damit Probleme haben (laut 
Wikipedia-Übersichten der Compiler). Das Nichtvorhandensein der Tools 
ist aber kein Problem der Sprache, sondern der Hersteller, aber auch der 
Kunden, denn Hersteller bauen ungern, was die Kunden nicht nachfragen. 
OSS ist da besser dran, da reicht es, wenn die Entwickler es wollen.
Ich muß aber zugeben, daß ich leicht reden hab und mir eben bei Bedarf 
den aktuellsten GCC selber baue und notfalls auch nichtmal 
GCC-offizielle Erweiterungen wie static_print auch mal selber 
rein-patchen kann und vor allem darf.

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

Ralf schrieb:
> Das war auch was, was mir durch den Kopf ging. Aber ist es nicht
> umständlich, wenn die Funktionen selbst parsen müssen? Das bläht doch
> immens auf, oder?

Schreibe mal einen kleinen Parser, der "read 0x1234" und "write 0x1234 
300" mit den Standardfunktionen versteht. Das ist mit strtok() und 
atoi() in wenigen Zeilen Code erledigt. Funktionsaufrufe sind billig.

Jede Funktion muss selbst wissen, welche Parameter sie hat. Dann kann 
sie sich auch selbst darum kümmern, die rauszupopeln. In den meisten 
Fällen ist das nicht schwer - siehe die Beispiele von oben.

In jedem Fall ist das schneller hingeschrieben und getestet als eine 
Parsergrammatik für yacc oder so.

von Axel S. (a-za-z0-9)


Lesenswert?

Nop schrieb:
> Man kann sich natürlich auch einfach einen Tokenizer schreiben (oder
> strtok nehmen) und dann mit einem endlichen Automaten arbeiten.

Genau das tun lex/yacc, antlr und andere Parsergeneratoren. Was die 
rauswerfen, ist eine Statemachine bzw. wenn man Lexer und Parser trennt, 
dann zwei. Der Vorteil ist hier, daß man die Grammatik in einer lesbaren 
Form schreiben kann. Das vereinfacht Fehlersuche und Erweiterung schon 
sehr.

Daß man ein paar Bytes mehr Flash braucht als mit der handgeschriebenen
Variante, ist mittlerweile egal. Die µC haben genug Resourcen. Und 
Geschwindigkeit ist bei einem Parser für eine Kommandozeile nun wirklich 
gar kein Thema.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Axel S. schrieb:
> Der Vorteil ist hier, daß man die Grammatik in einer lesbaren Form
> schreiben kann.

Der zweite Vorteil ist, dass man zwar ein bisschen initialen Aufwand
spendiert (sowohl bezüglich Arbeitszeit als auch memory footprint),
danach aber jegliche Erweiterungen saueinfach sind, sofern man nicht
gerade eine völlig verkorkste Grammatik verbockt hat.  Die Codegröße
steigt dann auch mit den Erweiterungen nur noch sehr langsam, da die
generierten Tabellen ziemlich effizient sind.  Dass den C-Code darin
kein Schwein lesen kann interessiert nicht, denn man muss ja nur den
Sourcecode auf lex/yacc-Ebene pflegen.

: Bearbeitet durch Moderator
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.