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 switch
wü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!
quelle
Antworten:
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 .
quelle
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.
quelle
Was Sie beschreiben, kommt einer Stapelsprache sehr nahe .
Zum Beispiel in Faktor würde das, was Sie beschreiben, so gemacht werden
Oder Sie können Ihre eigenen Wörter definieren und sie dann verwenden, wie z
Mit diesen Definitionen wird das obige Beispiel
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.
quelle
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.
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.
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.
Dann sollten Sie sich vielleicht die LISt-Verarbeitungssprache ansehen . Das Nebeneinander von Code und Daten sollte gut zu dem passen, was Sie beschreiben.
quelle