command parser als library function

Begonnen von martinp876, 30 Dezember 2021, 08:56:07

Vorheriges Thema - Nächstes Thema

martinp876

Nun, also darüber Nachdenkend (dauert immer etwas bei mir) wie man cmd-parsing und param-parsing zusammenfügen kann komme ich zu folgender abstrakten Darstellung:

cmdParser:
bekommt die Parameter geliefert und prüft diese. Wie schon angesprochen auf Anzahl, Inhalt,...
Es werden, wenn definiert, defaults gesetzt.
fhemWeb wird bedient mit "get/set ?" und listen-generierung bei ein-parameter kommandos.
=> aktuelle Implementierung geht(ging) von einer sequenziellen Parameterliste aus.

parseParams
Im Kernel wird der Input-String nach spaces (und tabs) in ein Array zerlegt.
ParseParams ist subtiler :
##>Sequenziell
Input wird gruppiert nach ->"'{}<- - und nachfolgend wie üblich nach "spaces" zerlegt.
(es sind weitere Delimiter möglich,... ggf später).

##>per schlüsselworten
Optional können parameter über keyswords identifizieren.


Zusammengefasstes modul
wie bisher kann man die Schlüsselwörter und ihre Optionen identisch zu den Parametern als Kommando definieren.
Ein Beispiel
CommandKey1   = "(on|off|maybe)  k1=(kv11|kv12|kv13) k2=(kv21|kv22|kv23)+ k4=-myval- k5=[-myval2-] k3=[(kv31|{kv32}|kv33)]";
das Kommando enthält einen sequentialparam und 3 keys.
k1 kann die Werte kv11,kv12 oder kv13 annehmen (alles andere ist nicht erlaubt, einer MUSS angegebn werden
k2 kann die Werte kv21,kv22 oder kv23 annehmen - mehrere sind möglich
k3 ist optional und kann die Werte nach Liste annehmen. Wenn nichts angegeben wird "kv32" gesetzt
k4 kann jeden wert annehmen, es muss angegeben werden
k5 kann jeden wert annehmen, es muss aber nicht.

=> syntaktiche Beschreibung wie bei Params.

Bin schon weit mit codieren, die Testbench ist gleich dabei. Es werden noch nicht alle falscheingaben abgefangen.

Angelehnt wir vor wird dem Modul immer ein vollständiger hash an keys übergeben - was die Auswergung einfacher macht.
Details sind zu klären: soll ein nicht eingegebener Wert "" oder undef enthalten? Sollten wir besprechen, wenn die Testbench öffentlich ist.



martinp876

anbei nun eine Testversion mit "names params" Unterstützung.

Zum Test das file einspielen und einmal intanziieren, damit man testen kann.
define mcao MCAO

Die Instanz ist natürlich nur zum Test notwendig,  nicht im Betrieb.
Hier sind schon Kommandos definiert, kann man anpassen, ist nur spielzeug. alles in "get" - set funktioniert analog

Der Programmierer definiert nun die Kommando Syntax und die Optionen so weit wie möglich. Je besser spezifiziert, desto besser die Prüfung.
Der Parser liefert Fehler bei Syntax Verletzung, fehlen den oder überzähligen Parametern, fehlenden oder überzähligen keys, setzt default werte wie definiert ein, liefert IMMER alle definierten keys, liefert die Fehlermeldung ,...
was eben so ein parser machen sollte.

get Testbench sendet gleich einmal eine Reihe von input und bereitet die Antworten auf.
parsParams ist funktional übernommen - weitgehend. sollten noch funktionen wie sonder-separatoren benötigt werden kann man das addieren.

Unklar und schwierig ist immer noch der Umgang mit Klammern
K1={adf asdfasdf } =>einfach
K1={adf as{{dfasdf } =>fehler?
K1={adf asdfasdf }sdf sdf => fehler? kein space nach }
K1= {adf asdfasdf }sdf sdf => fehler, space nach =
K1={adf asdfasdf} sdf sdf => ok
K1={adf as}dfasdf} sdf sdf => Fehler?


martinp876

Ich habe nun einmal definiert, dass
[=\s]" der Anfang der exception und "\s das Ende ist
[=\s]' der Anfang der exception und '\s das Ende ist
[=\s]{' der Anfang der exception und das "ausgezählte } das Ende ist

Beispiele sind dann
"aa \"asdf asdf sa\"asdf \" asdf" => 1)aa 2)"asdf asdf sa"asdf "  3)asdf
"aa \'asdf asdf sa\'asdf \' asdf" => 1)aa 2)'asdf asdf sa'asdf '  3)asdf
"aa \'asdf \"asdf sa\"asdf" \' asdf" => 1)aa 2)'asdf "asdf sa"asdf" '  3)asdf
"aa {asdf \"asdf sa} asdf asdf" => 1)aa 2){asdf "asdf sa} 3)asdf  4)asdf
"aa {asdf \"asdf sa}asdf asdf" => 1)aa 2){asdf "asdf sa} 3)asdf  4)asdf
"aa {asdf as{df sa}asd}f asdf" => 1)aa 2){asdf {asdf sa}asd} 3)f  4)asdf
"aa {asdf \"asdf sa}asdf {asdf s{df} asdf" => 1)aa 2){asdf "asdf sa} 3)asdf  4)asdf 5)s{df} 6)asdf

damit ist beispielhaft erklärt, wie mit "innenliegenden Sonderzeichen" umgegangen wird sowie mit "not matiching brackets.

Im Code anbei ist das realisiert.
Kommentare?