Wie würde ich etwas ähnliches zur Compiler-Anweisung Objective-C @encode () in ANSI C implementieren?

8

Die @encode-Direktive gibt ein const char * zurück, das ein codierter Typdeskriptor der verschiedenen Elemente des Datentyps ist, der übergeben wurde. Beispiel folgt:

%Vor%

Ich konnte mithilfe von sizeof () primitive Typen bestimmen - und wenn es ein vollständiges Objekt wäre, könnte ich die Klassenmethoden verwenden, um Introspektion zu machen.

Wie bestimmt es jedoch jedes Element einer undurchsichtigen Struktur?

    
Anderson 12.02.2010, 22:44
quelle

3 Antworten

14

@Lothars Antwort könnte "zynisch" sein, aber es ist leider ziemlich nah dran. Um etwas wie @encode() zu implementieren, benötigen Sie einen vollständigen Parser, um die Typinformationen zu extrahieren. Nun, zumindest für etwas anderes als "trivial" @encode() -Anweisungen (d. H.% Co_de%). Moderne Compiler haben in der Regel entweder zwei oder drei Hauptkomponenten:

  • Das Frontend.
  • Das Zwischenende (für einige Compiler).
  • Das Backend.

Das Front-End muss den gesamten Quellcode analysieren und wandelt den Quelltext im Grunde in ein internes "machine usable" -Formular um.

Das Backend übersetzt das interne, "machine usable" -Formular in ausführbaren Code.

Compiler, die ein "intermediate end" haben, tun dies typischerweise aus irgendeinem Grund: Sie unterstützen mehrere "Frontends", die möglicherweise aus völlig verschiedenen Sprachen bestehen. Ein weiterer Grund ist die Vereinfachung der Optimierung: Alle Optimierungsdurchgänge arbeiten an der gleichen Zwischendarstellung. Die @encode(char *) -Compiler-Suite ist ein Beispiel für einen "dreistufigen" Compiler. gcc könnte als "Zwischen- und Backend" -Stufencompiler betrachtet werden: Die "Low-Level-VM" ist die Zwischenrepräsentation und die gesamte Optimierung findet in dieser Form statt. llvm kann es auch bis zur letzten Sekunde in dieser Zwischendarstellung behalten - dies ermöglicht eine "Linktime-Optimierung". Der llvm -Compiler ist wirklich ein "Frontend", das (effektiv) clang Zwischendarstellung ausgibt.

Wenn Sie also llvm -Funktionalität zu einem 'existierenden' Compiler hinzufügen wollen, müssen Sie es wahrscheinlich als 'Quelle zu Quelle' 'Compiler / Präprozessor' verwenden. So wurden die ursprünglichen Compiler für Objective-C und C ++ geschrieben - sie analysierten den Quelltext der Eingabe und wandelten ihn in "plain C" um, das dann in den Standard-C-Compiler eingespeist wurde. Es gibt ein paar Möglichkeiten, dies zu tun:

Rollen Sie Ihre eigenen

  • Verwenden Sie @encode() und yacc , um einen ANSI-C-Parser zusammenzustellen. Sie brauchen eine Grammatik ANSI C-Grammatik (Yacc) ist eine gute Anfang. Eigentlich, um es klar zu sagen, wenn ich lex sage, meine ich wirklich bison und yacc . Und auch, lose, die anderen verschiedenen flex und yacc mögen C-basierte Tools: Zitrone , dparser , etc ...
  • Verwenden Sie lex mit Yapp oder EYapp , die Pseudo perl Klone in yacc sind. Wahrscheinlich besser für das schnelle Prototyping einer Idee im Vergleich zu C-based perl und yacc - es ist immerhin lex : Reguläre Ausdrücke, assoziative Arrays, keine Speicherverwaltung, etc.
  • Erstellen Sie Ihren Parser mit Antlr . Ich habe keine Erfahrung mit dieser Werkzeugkette, aber es ist ein anderes "Compiler Compiler" -Tool, das (scheint) eher auf Java-Entwickler ausgerichtet ist. Es scheint frei verfügbare C- und Objective-C-Grammatiken zu geben.

Hack ein anderes Werkzeug

Hinweis: Ich habe keine persönlichen Erfahrungen mit einem dieser Tools, um etwas wie perl hinzuzufügen, aber ich vermute, dass sie eine große Hilfe sein würden.

  • CIL - Keine persönliche Erfahrung mit diesem Tool, aber dafür gedacht, C-Quellcode zu analysieren und dann "damit zu arbeiten". Von dem, was ich aus den Dokumenten entnehmen kann, sollte dieses Tool Ihnen ermöglichen, die Typinformation zu extrahieren, die Sie benötigen würden.
  • Sparse - Sehenswert, aber nicht sicher.
  • clang - Habe es nicht zu diesem Zweck benutzt, aber angeblich war eines der Ziele, es für diese Art "leicht hackbar" zu machen von Sachen. Besonders (und wiederum, keine persönliche Erfahrung), das "Heavy Lifting" des ganzen Parsens zu machen, lässt Sie sich auf den "interessanten" Teil konzentrieren, der in diesem Fall Kontext- und syntaxsensitive Typinformationen extrahiert und diese dann konvertiert zu einer einfachen C-Zeichenfolge.
  • gcc Plugins - Plugins sind ein gcc 4.5 (welches die aktuelle Alpha / Beta-Version des Compilers ist) ) Feature und "möglicherweise" können Sie leicht in den Compiler einhängen, um die Typinformationen zu extrahieren, die Sie benötigen würden. Keine Ahnung, ob die Plugin-Architektur so etwas erlaubt.

Andere

  • Coccinelle - Dies wurde kürzlich mit einem Lesezeichen versehen, um es später anzuschauen. Dieses "könnte" in der Lage sein, zu tun, was Sie wollen, und "könnte" es ohne viel Aufwand tun können.
  • MetaC - Zuvor auch dieses Lesezeichen hinzugefügt.Keine Ahnung, wie nützlich das wäre.
  • mygcc - "Mach", was du willst. Es ist eine interessante Idee, aber es ist nicht direkt anwendbar auf das, was Sie wollen. Auf der Webseite: "Mygcc ermöglicht es Programmierern, ihre eigenen Prüfungen hinzuzufügen, die Syntax-, Kontrollfluss- und Datenflussinformationen berücksichtigen."

Links.

Bearbeiten Sie # 1, die Bonuslinks.

@Lothar macht einen guten Punkt in seinem Kommentar. Eigentlich wollte ich @encode() einbeziehen, aber es sieht so aus, als wäre es auf dem Weg verloren gegangen.

  • lcc - Der lcc C-Compiler. Dies ist ein C-Compiler, der zumindest hinsichtlich der Quellcode-Größe besonders klein ist. Es hat auch ein Buch , das ich sehr empfehlen kann.
  • tcc - Der lcc C-Compiler. Nicht ganz so pädagogisch wie tcc , aber auf jeden Fall immer noch sehenswert.
  • poc - Der lcc Objective-C-Compiler. Dies ist ein "Quelle zu Quelle" Objective-C-Compiler. Es analysiert den Objective-C-Quellcode und gibt einen C-Quellcode aus, den er dann an poc (gut, normalerweise gcc ) übergibt. Hat eine Anzahl von Objective-C Erweiterungen / Features, die nicht in gcc verfügbar sind. Auf jeden Fall einen Besuch wert.
johne 14.02.2010, 01:47
quelle
4

Sie würden dies implementieren, indem Sie zuerst den ANSI-C-Compiler implementieren und dann einige implementierungsspezifische Pragmas und Funktionen hinzufügen.

Ja, ich weiß, das ist eine zynische Antwort und ich akzeptiere die Downvotes.

    
Lothar 13.02.2010 11:18
quelle
2

Eine Möglichkeit wäre, einen Präprozessor zu schreiben, der den Quellcode für die Typdefinitionen liest und auch @encode ... durch das entsprechende Zeichenfolgenliteral ersetzt.

Ein anderer Ansatz, wenn Ihr Programm mit -g kompiliert wird, wäre das Schreiben einer Funktion, die die Typdefinition zur Laufzeit aus den Debug-Informationen des Programms liest oder gdb oder ein anderes Programm verwendet, um sie für Sie zu lesen und dann formatieren Sie es wie gewünscht. Der Befehl gdb ptype kann verwendet werden, um die Definition eines bestimmten Typs zu drucken (oder wenn dies nicht ausreicht, gibt es auch maint print type , das sicher viel mehr Informationen ausgibt, als Sie möglicherweise möchten).

Wenn Sie einen Compiler verwenden, der Plugins unterstützt (zB GCC 4.5), kann es auch möglich sein, einen zu schreiben Compiler-Plugin dafür. Ihr Plugin könnte dann die Typinformationen nutzen, die der Compiler bereits analysiert hat. Offensichtlich wäre dieser Ansatz sehr compilerspezifisch.

    
mark4o 12.02.2010 23:23
quelle