Wie soll ich eine Befehlsverarbeitungsanwendung implementieren?

9

Ich möchte eine einfache Proof-of-Concept-Anwendung (REPL) erstellen, die eine Nummer akzeptiert und dann Befehle für diese Nummer verarbeitet.

Beispiel: Ich beginne mit 1. Dann schreibe ich " add 2", es gibt mir 3. Dann schreibe ich " multiply 7", es gibt mir 21. Dann möchte ich wissen, ob es eine Primzahl ist, also schreibe ich " is prime" (auf die aktuelle Zahl - 21), es gibt mir falsch. " is odd" würde mir wahr geben. Und so weiter.

Für eine einfache Anwendung mit wenigen Befehlen switchwürde sogar eine einfache Anwendung zur Verarbeitung der Befehle ausreichen. Aber wenn ich Erweiterbarkeit möchte, wie müsste ich die Funktionalität implementieren? Benutze ich das Befehlsmuster? Erstelle ich einen einfachen Parser / Interpreter für die Sprache? Was ist, wenn ich komplexere Befehle wie " multiply 5 until >200" möchte ? Was wäre eine einfache Möglichkeit, es zu erweitern (neue Befehle hinzuzufügen), ohne es neu zu kompilieren?

Bearbeiten: Um ein paar Dinge zu klären, wäre mein Endziel nicht, etwas Ähnliches wie WolframAlpha zu machen, sondern einen Listenprozessor (von Zahlen). Aber ich möchte zuerst langsam anfangen (mit einzelnen Zahlen).

Ich denke an etwas Ähnliches wie an Haskell, um Listen zu verarbeiten, aber an eine sehr einfache Version. Ich frage mich, ob so etwas wie das Befehlsmuster (oder ein gleichwertiges Muster) ausreichen würde oder ob ich eine neue Minisprache und einen Parser erstellen muss, um meine Ziele zu erreichen.

Edit2: Danke für all die Antworten, alle waren sehr hilfreich für mich, aber Emmad Kareem hat mir am meisten geholfen, also werde ich es als Antwort wählen. Danke noch einmal!

Nini Michaels
quelle
2
Ich bekomme keine Gegenstimmen. Bitte geben Sie Ihren Grund an, damit ich meine Frage beim nächsten Mal besser formulieren kann.
Nini Michaels
2
Diese Frage gefällt mir sehr gut. Ich freue mich darauf zu sehen, welche Designs die Leute vorschlagen. Suchen Sie speziell nach objektorientiertem Design (Sie erwähnen das Befehlsmuster, bei dem es sich um ein OO-Muster handelt)?
Bjarke Freund-Hansen
danke :) ja, ich würde OOP bevorzugen, aber es macht mir nichts aus, wenn andere Methoden vorgeschlagen werden!
Nini Michaels
2
Es scheint eine Implementierung von Reverse Polish Notation zu sein , ein sehr cooles Programmierthema!
Alberto De Caro
2
Sie fallen wahrscheinlich Foul des Buches Klausel aus Welche Fragen sollte ich nicht hier fragen? in den FAQ, dh wenn Sie sich ein ganzes Buch vorstellen können, das Ihre Frage beantwortet, fragen Sie zu viel .
Mark Booth

Antworten:

5

Das klingt nach einem Dolmetscher. Es sieht so aus, als ob Sie sich mehr Sorgen um die Implementierung als um die detaillierte Funktionalität machen (ich vermute nur hier). Dieses erweiterte Projekt ist keine triviale Aufgabe. Stellen Sie sicher, dass Sie den Umfang klar studieren, da dies einen technischen Ansatz und keinen Ad-hoc-Entwicklungsansatz erfordert, um ein zuverlässiges Produkt zu erhalten, anstatt ein Produkt mit 1000 Patches, das manchmal nur funktioniert.

Entscheiden Sie sich für eine Syntax und seien Sie bereit, diese zu analysieren und die erforderlichen Syntaxprüfungen durchzuführen. Dieser Link kann Ihnen dabei helfen: Erstellen Sie Ihren eigenen Parser .

Schauen Sie sich Folgendes an: Dieses Thema berührt verschiedene Aspekte der Arbeit. Außerdem gibt es gute Links, die Ihnen helfen können (insbesondere die Antwort von RMK).: Erstellen eines Sprachdolmetschers . Vielleicht möchten Sie ein Beispiel für ein gut aussehendes Projekt sehen, das unter: Ultimate Programmable Scientific Calculator etwas ähnlich ist . Den Quellcode und das Arbeitsprogramm für einen Befehlszeilen-C # -Interpreter finden Sie hier. Befehlszeilenimplementierung von C # -Made-for-Teaching . Die Verwendung des Compilers zur Ausführung komplexer Aufgaben wie Parsen, Variablentippen usw. kann eine clevere Möglichkeit sein, sich der Komplexität zu entziehen, all dies selbst zu schreiben. Außerdem gibt es die Mono-Option, die eine Charp-Shell-Funktion bietet, die Sie sich ansehen sollten: CsharpRepl .

Keine Chance
quelle
Danke, deine Links sind wirklich hilfreich! Ich denke, ein Dolmetscher wäre die beste Wahl, wenn ich ihn einfach erweitern möchte.
Nini Michaels
Vielen Dank für das Feedback. Ich denke, es ist eine gute Idee, mit dem Link zum CodeProject zu beginnen.
NoChance
2

Sofern Sie nicht speziell daran interessiert sind, den eigentlichen Parser für sich selbst zu schreiben, würde ich empfehlen, sich eines der Parser-Generator-Frameworks anzusehen. Für C haben Sie YACC oder Bison , aber es sollte andere Alternativen für andere Sprachen geben, wenn Sie es vorziehen.

Dadurch wird die Komplexität des Parsens komplexer Grammatiken verringert, und Sie können sich auf die Aufgabe konzentrieren, die Sie ausführen möchten. Natürlich mag dies für die Grammatik, die Sie in der Frage vorschlagen, übertrieben sein, aber da Sie erwähnen, dass Sie später die Möglichkeit haben, auf eine komplexere Grammatik zu erweitern, lohnt es sich zumindest, sich von diesen Frameworks inspirieren zu lassen.

harald
quelle
1
Das Problem bei den meisten Parser-Generatoren besteht darin, dass ihre Artefakte statisch sind und sich nicht leicht erweitern lassen. Ich denke, OP wäre besser mit einer Regel-Engine zu bedienen, bei der die "Regeln" (Schlüsselwörter und Syntax) in einer flexiblen Datenstruktur gespeichert und nach jeder Eingabe ausgewertet werden.
TMN
2

Was Sie beschreiben, kommt einer Stapelsprache sehr nahe .

Zum Beispiel in Faktor würde das, was Sie beschreiben, so gemacht werden

1
2 +
7 *
even? not

Oder Sie können Ihre eigenen Wörter definieren und sie dann verwenden, wie z

: add ( x y -- sum ) + ;
: multiply ( x y -- product ) * ;
: odd? ( n -- ? ) even? not ;

Mit diesen Definitionen wird das obige Beispiel

1
2 add
7 multiply
odd?

Normalerweise sind Stapelsprachen trivial zu analysieren, da sie einzelne Wörter verwenden, die durch Leerzeichen getrennt sind. Ich schlage vor, Sie werfen einen Blick auf Faktor - es kann genau das sein, was Sie wollen. Es sollte einfach sein, die Wörter zu definieren, die die von Ihnen benötigte Verarbeitung ausführen.

EDIT : Wenn Sie tatsächlich eine ähnliche Sprache entwerfen möchten, schlage ich vor, dass Sie trotzdem mit einer von ihnen spielen. Das Parsen einer Stapelsprache ist trivial - Sie teilen sich Leerzeichen auf, und eine naive Implementierung der Verarbeitung ist einfach: Sie müssen sich nur darum kümmern, was auf einem Stapel passiert.

Andrea
quelle
Das klingt ziemlich einfach und ist ein guter Anfang. Vielen Dank!
Nini Michaels
1

Aber wenn ich Erweiterbarkeit möchte, wie müsste ich die Funktionalität implementieren?

Das solltest du nicht. Die Erweiterbarkeit schafft eine Menge Komplexität bei sehr geringem Gewinn. Das heißt, Sie müssen einen Haken in den vorhandenen Zustand bereitstellen. Eine Möglichkeit, den Status anzuzeigen, den Status zu ändern und einen Mechanismus zum Zurückgeben anderer Ergebnisse bereitzustellen (Drucken auf dem Bildschirm). Sie benötigen eine Möglichkeit für den Kerncode, Module zu erkennen, zu laden und Befehle an sie zu senden.

Benutze ich das Befehlsmuster?

Sie können, aber es ist wahrscheinlich nicht angemessen.

Sie nehmen nicht die gesamte Eingabe und senden sie zur Verarbeitung ab, sondern analysieren die Eingabe, senden sie an den richtigen Handler und lassen sie ihre Arbeit erledigen. Der Befehl variiert in dieser Kommunikation nicht. also kein befehlsmuster.

Erstelle ich einen einfachen Parser / Interpreter für die Sprache?

Sie benötigen etwas, um die Eingabe in Token aufzuteilen. Für eine erweiterbare Lösung werden Sie wahrscheinlich nicht viel mehr tun. Für eine genau definierte Lösung bietet ein vollständiger Analysebaum eine bessere Leistung, Fehlerbehandlung und Debug-Fähigkeit.

sondern eine Liste (von Zahlen) Prozessor

Dann sollten Sie sich vielleicht die LISt-Verarbeitungssprache ansehen . Das Nebeneinander von Code und Daten sollte gut zu dem passen, was Sie beschreiben.

Telastyn
quelle
Vielen Dank für die Vorschläge. Was LISP betrifft, bin ich damit vertraut und noch vertrauter mit Haskell, was mich zu dieser Idee inspiriert hat. Obwohl ich das Rad vielleicht ein bisschen neu erfinde, möchte ich mir die Hände schmutzig machen, wenn ich Befehle verarbeite und sie interpretiere. Es hat also neben der eigentlichen "Listenverarbeitung" auch einen pädagogischen Zweck :)
Nini Michaels
@NiniMichaels sicherlich, aber was das Design für Erweiterbarkeit angeht, ist es keine schlechte Option, die Organisation / Verkettung von Code / Daten von lisp zu verwenden.
Telastyn