Ich mache einen 8051 Assembler.
Vor allem ist ein Tokenizer, der die nächsten Token liest, Fehlerflags setzt, EOF usw. erkennt Dann gibt es die Hauptschleife des Compilers, der die nächsten Token liest und nach gültigen Mnemonics sucht:
%Vor%Und es geht weiter zu mehreren Fällen. Schlimmer noch als das ist der Code in jedem Fall, der nach gültigen Parametern sucht und sie dann in kompilierten Code konvertiert. Im Moment sieht es so aus:
%Vor%Für jeden der Mnemonics muss ich nach gültigen Parametern suchen und dann den korrekten kompilierten Code erstellen. Sehr ähnliche Codes für die Überprüfung der gültigen Parameter für jeden mnemonic Wiederholung in jedem Fall.
Gibt es also ein Entwurfsmuster, um diesen Code zu verbessern?
Oder einfach eine einfachere Möglichkeit, dies zu implementieren?
Edit: Ich habe die Antwort von Plinth angenommen, danke an ihn. Trotzdem, wenn Sie Ideen dazu haben, werde ich glücklich sein, sie zu lernen. Danke allen.
Ich habe im Laufe der Jahre eine Anzahl von Assembler geschrieben, die Hand-Parsing machen, und ehrlich gesagt, ist es wahrscheinlich besser, eine Grammatiksprache und einen Parser-Generator zu benutzen.
Hier ist der Grund: Eine typische Fertigungslinie sieht wahrscheinlich so aus:
%Vor%und eine Anweisung lautet:
%Vor%und eine Direktive wird sein:
%Vor%usw.
Mit einem anständigen Parsergenerator wie Gold solltest du in wenigen Stunden eine Grammatik für 8051 knacken können. Der Vorteil gegenüber der manuellen Analyse besteht darin, dass Sie in Ihrem Assemblercode so viele komplizierte Ausdrücke haben können wie:
%Vor%was mit der Hand ein echter Bär sein kann.
Wenn Sie es von Hand machen möchten, erstellen Sie eine Tabelle aller Ihrer Mnemotechniken, die auch die verschiedenen zulässigen Adressierungsmodi enthalten, die sie unterstützen, und für jeden Adressierungsmodus die Anzahl der Bytes, die jede Variante benötigt, und den Opcode für es. Etwas wie das:
%Vor%Dann haben Sie eine Liste aller Anweisungen, die wiederum eine Liste aller Adressierungsmodi enthält.
So wird Ihr Parser etwa so:
%Vor%Ich denke, du solltest dir das Besuchermuster ansehen. Es macht Ihren Code vielleicht nicht viel einfacher, reduziert aber die Kopplung und erhöht die Wiederverwendbarkeit. SableCC ist ein Java-Framework zum Erstellen von Compilern, die es umfassend verwenden.
Als ich mit einem Microcode-Emulator-Tool spielte, konvertierte ich alles in Nachkommen einer Instruction
-Klasse. Von Instruction
waren Kategorieklassen wie Arithmetic_Instruction
und Branch_Instruction
. Ich habe ein factory -Muster verwendet, um die Instanzen zu erstellen.
Ihre beste Wette könnte sein, die Syntaxspezifikation für die Assemblersprache zu bekommen. Schreiben Sie einen Lexer , um in Token zu konvertieren (** bitte verwenden Sie keine if-elsif-else-Leitern). Stellen Sie dann basierend auf der Semantik den Code aus.
Vor langer Zeit waren Assembler mindestens zwei Durchgänge: Der erste, der Konstanten auflöst und den Skelettcode bildet (einschließlich Symboltabellen). Der zweite Durchlauf bestand darin, konkretere oder absolute Werte zu erzeugen.
Hast du in letzter Zeit das Drachenbuch gelesen?
Haben Sie sich das Muster "Command Dispatcher" angesehen?
Die allgemeine Idee wäre, ein Objekt zu erstellen, das jeden Befehl (Befehl) behandelt, und eine Nachschlagetabelle zu erstellen, die jeden Befehl der Handler-Klasse zuordnet. Jede Befehlsklasse hätte eine gemeinsame Schnittstelle (zum Beispiel Command.Execute (* args)), die Ihnen definitiv ein saubereres / flexibleres Design als Ihre aktuelle, enorme switch-Anweisung geben würde.
Tags und Links c++ assembly design-patterns compiler-construction compiler-design