Shell/Konsole schreiben
-
Ja das stimmt schon, aber es sollte hald möglich sein, die neuen Befehle schnell einzufügen, da es um die 50 Befehle sind. Außerdem können ständig neue Befehle hinzugefügt werden.
-
Ja, dann bau Dir halt nen Container mit Befehlen mit Anzahl der Parameter, bau Dir nen gleichen Tokenizer und daraufhin nen Parser und dann läuft das.
Oder wenn Du nur einen Befehl pro Zeile brauchst, ist das Parsen ja noch einfacher. Dann nimmst du irgendwas von boost mit regex oder ein paar weiteren Stringfunktionen oder du machst das klassisch.
Wenn Du hinter jedem Befehl eine Funktion haben möchtest, brauchst Du natürlich entsprechend viele Implementierungen. Anbieten könnte sich z.B. eine map mit Funktionszeigern. Aber dafür stellt sich die Frage, ob die Parameter und Rückgabetypen der Funktionen gleich sind oder nicht. Was sollen das denn für Funktionen sein?
-
ja es sollte hinter jedem befehl eine funktion stehen.
was dann in diesen funktionen gemacht wird ist ja prinzipiell egal. was mir allerdings wichtig ist, ist das programm z.b erkennt ob die richtigen paramter eingegeben wurden, ob die parameter den richtigen typ haben und ob sie im richtigen bereich liegen.
es wäre hald schön wenn man diese überprüfung nicht für jeden befehl einzeln eingeben muss. ich hoffe das war jetzt verständlich ausgedrückt. Danke im voraus für eure hilfe!
-
Wenn du das automatisieren willst, wird das aber nicht so einfach mit der Parameterüberprüfung. Das ist ein ziemliches Gefrickel. Wenn Du wüsstest, dass die Parameter einfach immer double sein könnten und der Rückgabetyp void ist, könnte ich was basteln.

-
wenn ichs richtig sehe bestimmt das erste Wort, welche Funktion aufgerufen wird. Gib dann einfach den Rest der Zeile als einen String an die jeweilige Funktion weiter, die soll dann selbst entscheiden, ob die Parameter passen. Die Implementierung wird dadurch auch einfacher, da du dann alle Funktionen die selbe Signatur haben und du nurnoch anhand des ersten Wortes die richtige Funktion aus einer map<string, void (*)(string const&)> heraussuchen kannst.
Die Überprüfung der Parameter kannst du dir ggf. mit einem kleinen Framework erleichtern, das dir aus den parameter-strings die richtigen Parameter rauspult und bei Misserfolg einen Fehler ausgibt.
-
Ja, der Rückgabetyp der Funktion ist immer void. Wenn es mit den Paramtertyp double geht wär das ja schon mal ein Anfang.
Das ließe sich dann später ja vielleicht einmal erweitern.
Ich bin im moment echt ziemlich verzweifelt.
-
Wie gesagt, übergib die Parameter als string an die Funktionen und parse bei Bedarf in der jeweiligen Funktion deinen double daraus.
-
Vor 2 Jahren wurde so was ähnliches schon einmal durchdiskutiert.
Was haltet ihr von dieser möglichkeit?Och, so schwer ist das gar nicht. Du solltest halt nicht damit anfangen, die beste Konsole/Shell der Welt zu schreiben, sondern eher in kleinen und schnellen Schritten vorwärts.
Ich geb dir mal ne Struktur vor
:
1. Grundgerüst, also einfache Schleife, vor jeder Eingabe wird "> " (oder so) ausgegeben und du kannst Befehle einlesen (mit std::getline), ohne Parsing oder weitere Verarbeitung.2. Du implementierst super-einfache Befehle, z.B. "hallo" und "exit", wobei bei "hallo" auch irgendeine Begrüßung kommt, bei exit wird die Schleife und damit das Programm verlassen.
3. Du überlegst dir eine gute Struktur, die Befehle zu verarbeiten (if (str=="hallo") {...} else if (str=="exit") {...} wäre z.B. nicht gut). Evtl bietet sich hier eine map an, die Strings nach Funktionszeigern mappt. Dann kannst du mit if ( mymap.find(input) != mymap.end() ) rausfinden, ob der Befehl existiert und mit mymap[input](); die Funktion aufrufen, die dann den Befehl ausführt (also für jeden Befehl eine Funktion).
4. Argumente für die Befehle parsen, also bis Klammer ist der Befehl, danach bis zur hinteren Klammer die Texte zwischen den Kommata extrahieren. Die Texte bzw Parameter in vector<string> oder so speichern und der entsprechenden Befehlsfunktion mit übergeben. Die wertet die Parameter dann aus, also wandelt sie in entsprechend be-typ-te Variablen um und agiert dann je nach Parametern.
Oder so
-
Ja, so was habe ich hier Mal gebastelt, habe aber das Parsen weggelassen, weil ich da gerade noch keine super-schöne Lösung gefunden habe:
#include <iostream> #include <string> #include <vector> #include <map> class Command { private: void* funcPtr_; unsigned int arguments_; public: Command(void* funcPtr, unsigned int arguments) : funcPtr_(funcPtr), arguments_(arguments) {} void operator()(const std::string& argumentString) { std::vector<double> argumentList; // Nach eigenem Bedarf argumentString nach Argumenten parsen std::assert(argumentList.size() == arguments_); switch(argumentList.size()) { case 0: (*reinterpret_cast<void(*)()>(funcPtr_))(); break; case 1: (*reinterpret_cast<void(*)(double)>(funcPtr_))(argumentList[0]); break; case 2: (*reinterpret_cast<void(*)(double, double)>(funcPtr_))(argumentList[0], argumentList[1]); break; } } }; void sleep(double seconds) {/* ... */} void punch(double lowPunchs, double highPunchs) {/* ... */} int main() { std::map<std::string, Command> CommandMap; CommandMap.insert(std::pair<std::string, Command>("sleep", Command(&sleep, 1))); CommandMap.insert(std::pair<std::string, Command>("punch", Command(&punch, 2))); std::string blub; while(std::getline(std::cin, blub)) { std::string command; std::string argumentPart; // Von blub den Teil vor der Klammer und zwischen den Klammern parsen CommandMap[command](argumentPart); } int u; std::cin >> u; }
-
Für den Anfang und mit 50 Befeheln reicht doch auch etwas ganz leichtes, sowas zb:
#include <iostream> #include <map> #include <cstdlib> //für exit void help() { std::cout << "Auflistung aller Befehle:\n"; //... } void exit() { exit(0); } int main(int argc, char **argv) { std::map<std::string, void (*)()> befehl_normal; befehl_normal["help"] = &help; befehl_normal["exit"] = &exit; std::string eingabe; for(;;) { std::cout << argv[0] << " >> "; std::getline(std::cin, eingabe); if(befehl_normal.find(eingabe) != befehl_normal.end()) //ist der befehl vorhanden? { befehl_normal[eingabe](); //wenn ja, fuer aus } else { std::cerr << "Der Befehl \"" << eingabe << "\" ist entweder falsch geschrieben\n" "oder ist nicht vorhanden.\n"; } } }Und das könnte man für den Anfang noch weiter ausbauen. Für 50 Befehle reicht das, und wenn das Prog nur die Konsole sein soll braucht es auch nicht mehr, finde ich.
-
Er wollte aber Parameter haben.
-
Gibt es da eigentlich auch eine Möglichkeit mit Templates? Mir fällt da nichts ein.
-
Wie, mit Templates? Ein Klassentemplate kann man nicht als Typ einer Map/eines Vectors nehmen oder was willst Du templatisieren? Oder mit diesen neuen variablen Argumenten?
-
Eisflamme schrieb:
Ein Klassentemplate kann man nicht als Typ einer Map/eines Vectors nehmen
Wie meinst du das? Das versteh ich nicht. Meinst du sowas
std::vector<TemplateKlasse<Typ>> array? Und wiese geht das eigentlich nicht ohne Typ, sodass man dann sowas hat:
std::vector<TemplateKlasse> array; array.push_back(TemplateKlasse<int>); //hier ein objekt mit typ int hinzufügen array.push_back(TemplateKlasse<char>); //hier mit charKann man das irgendwie erreichen?
-
Vorsicht, Du meinst mit Templateklasse gerade Klassentemplate.

Das geht nicht, weil das unterschiedliche Typen sind. Du kannst eine abstrakte Klasse in einen Container stecken, aber das Klassentemplate ist ja kein Typ, bevor es nicht typisiert ist.
Man kann das erreichen, indem man noch Vererbung dazu bastelt...
class HiIAmRandy { public: virtual callMethode(std::string&) = 0; }; template<class T> class IKilledYouInThePastSeveralTimes : public HiIAmRandy { public: virtual callMethode(std::string&) {/* Parsen und methode aufrufen */} void methode(T bla) {} }; std::vector<HiIAmRandy*> einVectorEinVectorHurra;Na ja, aber das nützt nichts. Wenn ich nämlich von diesem Objekt was in den vector schreibe, geht der Funktionspointer logischerweise auch nicht auf ein Funktionstemplate, sondern nur auf eine Templatefunktion und damit bringt mir die Flexibilität durch das Template wieder nichts, weil ich für jeden Typ was in die map schieben muss... Vielleicht ist das einer der seltenen Fälle, wo boost::any Sinn machen würde. Aber double deckt eh fast alles ab, also wird das wohl reichen.
-
Ich habe mittlerweile begonnen die konsole zu schreiben.
Die Eingabe durch den Benutzer erfolgt nun durch folgendes Muster:befehlsname par1 par2 par3Das Parsen der Eingabe hab ich folgendermaßen realisiert:
int main( int argc, char * argv[] ) { while(1) { parse( argc, argv ); } } void parse(int argc, const char * const * argv) { vector<string> args; for (int i = 0; i < argc; i++) args.push_back(argv[i]); }Die strings werden anschließen in die entsprechenden Variablentypen umgewandelt.
Nun wäre es noch schön, in der Konsole zusätzlich eine "history" (mit pfeiltaste oben) und eine "autovervollständigung" (tabulator) einzurichten.
Hat jemand eine Idee wie man das machen könnte?
Gibt es dazu für Linux Bibliotheken die einem sowas erleichtern?
Danke für alle die sich Zeit nehmen dies durchzulesen.
-
hallo 123 schrieb:
Nun wäre es noch schön, in der Konsole zusätzlich eine "history" (mit pfeiltaste oben) und eine "autovervollständigung" (tabulator) einzurichten.
Hat jemand eine Idee wie man das machen könnte?Nicht mit Standard-C++ Bordmitteln. Das kennt nämlich keine Pfeiltaste und Tabulatortaste - und in der Konsole den Befehl zu verfollständigen klappt auch nur mit OS-Spezifischen Konsole-Funktionen.
Daher stell deine Frage am besten im jeweiligen OS-Unterforum in einem neuen Thread
-
hallo 123 schrieb:
void parse(int argc, const char * const * argv) { vector<string> args; for (int i = 0; i < argc; i++) args.push_back(argv[i]); }WArum nicht einfach per
vector<string> args(argv,argv+argc);Nun wäre es noch schön, in der Konsole zusätzlich eine "history" (mit pfeiltaste oben) und eine "autovervollständigung" (tabulator) einzurichten.
Hat jemand eine Idee wie man das machen könnte?
Gibt es dazu für Linux Bibliotheken die einem sowas erleichtern?
Danke für alle die sich Zeit nehmen dies durchzulesen.Da mußt du die Tasten in deinem Programm abfangen (das geht nicht mit C++ Bordmitteln, aber mit Funktionen deines Systems) und darauf reagieren.
-
Daher stell deine Frage am besten im jeweiligen OS-Unterforum in einem neuen Thread

Danke, das werd ich gleich machen!