Frage

Dies ist eine eher theoretische Frage zu Makros (glaube ich).Ich weiß, dass Makros Quellcode verwenden und Objektcode erzeugen, ohne ihn auszuwerten, wodurch Programmierer vielseitigere syntaktische Strukturen erstellen können.Wenn ich diese beiden Makrosysteme klassifizieren müsste, würde ich sagen, dass es das Makro „C-Stil“ und das Makro „Lisp-Stil“ gibt.

Es scheint, dass das Debuggen von Makros etwas knifflig sein kann, da zur Laufzeit der tatsächlich ausgeführte Code von der Quelle abweicht.

Wie verfolgt der Debugger die Ausführung des Programms anhand des vorverarbeiteten Quellcodes?Gibt es einen speziellen „Debug-Modus“, der eingestellt werden muss, um zusätzliche Daten über das Makro zu erfassen?

Ich kann verstehen, dass Sie in C einen Kompilierungszeitschalter für das Debuggen festlegen würden, aber wie würde eine interpretierte Sprache, wie etwa einige Formen von Lisp, das tun?

Es tut mir leid, dass ich das nicht ausprobiert habe, aber die Lisp-Toolchain erfordert mehr Zeit, als ich aufwenden muss, um sie herauszufinden.

War es hilfreich?

Lösung

Ich glaube nicht, dass es einen grundlegenden Unterschied zwischen Makros im „C-Stil“ und „Lisp-Stil“ in der Art und Weise gibt, wie sie kompiliert werden.Beide transformieren die Quelle, bevor der Compiler sie sieht.Der große Unterschied besteht darin, dass die Makros von C den C-Präprozessor verwenden (eine schwächere Sekundärsprache, die hauptsächlich für die einfache Zeichenfolgenersetzung dient), während die Makros von Lisp in Lisp selbst geschrieben sind (und daher überhaupt alles tun können).

(Nebenbei:Ich habe seit einiger Zeit kein nicht kompiliertes Lisp mehr gesehen ...sicherlich nicht seit der Jahrhundertwende.Aber wenn überhaupt, scheint die Interpretation das Makro-Debugging-Problem einfacher und nicht schwieriger zu machen, da Sie über mehr Informationen verfügen.)

Ich stimme Michael zu:Ich habe keinen Debugger für C gesehen, der überhaupt Makros verarbeitet.Code, der Makros verwendet, wird transformiert, bevor etwas passiert.Der „Debug“-Modus zum Kompilieren von C-Code bedeutet im Allgemeinen nur, dass es speichert Funktionen, Typen, Variablen, Dateinamen und dergleichen – Ich glaube nicht, dass sie Informationen über Makros speichern.

  • Zum Debuggen von Programmen, die Verwenden Sie Makros, LISP ist so ziemlich das gleiche wie C hier:Ihr Debugger sieht den kompilierten Code und nicht die Makroanwendung.Normalerweise werden Makros einfach gehalten und unabhängig voneinander vor dem Gebrauch debuggen, um dies zu vermeiden, genau wie C.

  • Zum Debuggen der Makrossich, Bevor Sie es irgendwohin verwenden, verfügt Lisp -Funktionen, die dies einfacher machen als in C, z.macroexpand-1 (Obwohl in C es offensichtlich eine Möglichkeit gibt, eine gesamte Datei vollständig und gleichzeitig zu macroexpand).Sie können den Vorher -herd einer Makroexpansion genau in Ihrem Editor sehen, wenn Sie ihn schreiben.

Ich kann mich nicht erinnern, dass ich jemals auf eine Situation gestoßen bin, in der es um das Debuggen ging hinein Eine Makrodefinition selbst wäre nützlich gewesen.Entweder handelt es sich um einen Fehler in der Makrodefinition macroexpand-1 isoliert das Problem sofort, oder es handelt sich um einen darunter liegenden Fehler. In diesem Fall funktionieren die normalen Debugging-Funktionen einwandfrei und es ist mir egal, dass zwischen zwei Frames meines Aufrufstapels eine Makroexpansion aufgetreten ist.

Andere Tipps

in lispworks Entwickler können die Schrittwerkzeug .

lispzeuge liefert einen Schritt, wo man durch den vollen Makro-Erweiterungsprozess .

Sie sollten sich wirklich auf die Art der Unterstützung untersuchen, die schläger hat, um Code mit Makros zu debuggen. Diese Unterstützung hat zwei Aspekte, wie Ken erwähnt. Auf der einen Seite gibt es das Problem des Debugging-Makros: In der gemeinsamen Lispen ist der beste Weg, um dies einfach zu erweitern, um Makro-Formulare manuell zu erweitern. Mit CPP ist die Situation ähnlich, aber primitiver - Sie würden den Code nur durch die CPP-Erweiterung ausführen und das Ergebnis inspizieren. Beide sind jedoch nicht ausreichend für mehr beteiligte Makros, und dies war die Motivation für ein Makro Debugger in Schläger - Es zeigt Ihnen die Syntax-Erweiterungsschritte nacheinander, mit zusätzlichen GUI-basierten Anzeigen für Dinge wie gebundene Identifikatoren usw.

Auf der Seite von mit macros wurde Racket immer fortgeschrittener als andere Regel- und Lisp-Implementierungen. Die Idee ist, dass jeder Ausdruck (als syntaktisches Objekt) der Code plus zusätzliche Daten ist, das seinen Quellort enthält. Auf diese Weise, wenn ein Formular ein Makro ist, hat der erweiterte Code, der mit dem Makro kommenden Teilen aufweist, den richtigen Quellort - von der Definition des Makros anstelle von seiner Verwendung (wo die Formulare nicht wirklich vorhanden sind). Einige Regel- und Lisp-Implementierungen werden mit der Identität von Unterformen, wie dmitry-vk erwähnt, ein begrenztes Implementieren.

Ich weiß nicht über Lisp-Makros (was ich vermute, wahrscheinlich ganz anders als C-Makros) oder Debugging, aber viele - wahrscheinlich die meisten - C / C ++ -Bluggiers handhaben nicht besonders gut mit dem Debugging von C-Vorverarbeitung von C-Prepocessor-Makros.

allgemein, c / c ++ -debvers sie nicht in die makrodefinition.Wenn sich ein Makro in mehreren Anweisungen ausdehnt, bleibt der Debugger in der Regel einfach auf derselben Quelllinie (wo das Makro aufgerufen wird) für jeden Debugger-Schritt 'Schritt'.

Dies kann das Debuggen von Makros etwas schmerzhafter machen, als sie ansonsten sein könnten - ein weiterer Grund, sie in C / C ++ zu vermeiden.Wenn ein Makro auf wirklich mysteriöse Weise fehlgespannt ist, fälle ich in den Assembly-Modus, um ihn zu debuggen oder das Makro (entweder manuell oder mit dem Switch des Compilers) zu erweitern.Es ist ziemlich selten, dass Sie ins extreme gehen müssen;Wenn Sie Makros schreiben, die so kompliziert sind, nehmen Sie wahrscheinlich den falschen Ansatz ein.

In der Regel in der Debugging von C-Quellenebene hat die Leitungsgranularität ("Nächstes" Befehl) oder Anweisungsgranularität ("Schritt in"). Makro-Prozessoren Legen Sie spezielle Richtlinien in die verarbeitete Quelle ein, mit denen der Compiler kompilierte Sequenzen von CPU-Anweisungen an Quellcode-Linien aufzeichnen kann.

In LISP gibt es keine Übereinkommen zwischen Makros und Compiler, um den Quellcode an das kompilierte Code-Mapping zu verfolgen, sodass es nicht immer möglich ist, ein einzelnes Treten im Quellcode zu erstellen.

naheliegende Option ist, ein einzelnes Treten in einem Macroexpanded-Code zu tun. Der Compiler sieht bereits Finale, erweitert, Version des Codes und kann Quellcode an das Maschinencode-Mapping verfolgen.

Andere Option ist die Verwendung der Tatsache, dass LISP-Ausdrücke während der Manipulation Identität aufweisen. Wenn das Makro einfach ist und nur Zerstäubung und Einfügungscode in der Vorlage tätigt, sind einige Ausdrücke von erweiterten Code identisch (in Bezug auf den EQ-Vergleich) zu Ausdrücken, die aus Quellcode gelesen wurden. In diesem Fall kann der Compiler einige Ausdrücke von erweiterten Code zu Quellcode zuordnen.

Die einfache Antwort ist, dass es kompliziert ist ;-) Es gibt verschiedene Dinge, die dazu beitragen, ein Programm debuggen zu können, und sogar mehr zum Nachverfolgen von Makros.

In C und C ++ wird der Präprozessor verwendet, um Makros zu erweitern und in den tatsächlichen Quellcode einzuwählen. Die ursprünglichen Dateinamen und Zeilennummern werden in dieser erweiterten Quelldatei mit #line-Richtlinien verfolgt.

http://msdn.microsoft.com/ en-us / library / b5w2czay (vs.80) .aspx

Wenn ein C- oder C ++ -Ger-Programm mit aktiviertem Debugging kompiliert ist, erzeugt der Assembler zusätzliche Informationen in der Objektdatei, die Source-Linien, Symbolnamen, Typ-Deskriptoren usw. angibt.

http://sources.redhat.com/gdb/onlinedocs/stabs.html

Das Betriebssystem verfügt über Funktionen, mit denen ein Debugger möglich ist, um an einem Prozess anzuhängen und die Prozessausführung zu steuern; Pausieren, einzelner Schritt usw.

Wenn ein Debugger an das Programm angeschlossen ist, übersetzt er den Prozessstapel und den Programmzähler wieder in symbolisches Formular, indem er die Bedeutung von Programmadressen in den Debugging-Informationen aufnimmt.

dynamische Sprachen führen in der Regel in einer virtuellen Maschine aus, unabhängig davon, ob es sich um einen Interpreter oder einen Bytecode VM handelt. Es ist der VM, der Haken bereitstellt, damit ein Debugger den Programmfluss steuern und den Programmstatus inspizieren kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top