# dbg2lsp Instrumentiert AutoLISP-Funktionen (`.lsp`) automatisch mit den `ssg_dbg.lsp`-Routinen (`dbgf`, `dbg`, `dbgreturn`, `dbgopen`, `dbgclose`) - so wie es beim manuellen Debuggen bereits von Hand gemacht wird (siehe z.B. `Lisp/KreiselInsert.lsp::ils-eckrad-insert`). Erspart das muehsame und fehleranfaellige manuelle Einfuegen dieser Aufrufe in lange Aufrufketten (Kreisel/VarioFoerderer/Gefaellestrecke/Separator-Scanner o.ae.), bevor ein Testlauf in BricsCAD gestartet wird. - [Aufruf](#aufruf) - [Was wird eingefuegt](#was-wird-eingefuegt) - [--method](#--method) - [--recursive](#--recursive) - [--add-open](#--add-open) - [Schalter](#schalter) - [Typischer Ablauf](#typischer-ablauf) - [Beispiele](#beispiele) - [Funktionsweise / Aufloesung](#funktionsweise--aufloesung) - [Grenzen](#grenzen) - [Idempotenz](#idempotenz) ## Aufruf ``` bin\dbg2lsp.bat [--method NAME ...] [--recursive] [--add-open DATEI METHODE] [Schalter] ``` Das Batch-Skript ruft `setenv.bat` auf und startet `lib/dbg2lsp.py` mit den uebergebenen Argumenten. `` dient als Anker (ihr Verzeichnis wird immer mitdurchsucht) - die gesuchte Funktion muss nicht zwingend in genau dieser Datei stehen, siehe [Funktionsweise](#funktionsweise--aufloesung). ## Was wird eingefuegt ### --method Fuer die angegebene Funktion (mehrfach angebbar) wird direkt als erste Rumpf-Form ```lisp (dbgf "funktionsname") (dbg 'parameter1) (dbg 'parameter2) ... ``` eingefuegt (ein `dbg`-Aufruf je Eingabeparameter - die Locals nach `/` in der Parameterliste NICHT, das sind keine Eingabewerte), und die **letzte Form des Funktionsrumpfs** wird eingeklammert: ```lisp (dbgreturn ) ``` `dbgreturn` loggt und liefert den Rueckgabewert unveraendert weiter (siehe `Lisp/ssg_dbg.lsp`) - das Verhalten der Funktion aendert sich dadurch nicht. ### --recursive Verfolgt zusaetzlich den Aufrufgraphen: jede Funktion, die im (Original-)Rumpf aufgerufen wird - auch beliebig verschachtelt, z.B. in einem `if`/`progn`, aber NICHT innerhalb einer `'quotierten Liste` (die ist reine Datenliste, z.B. `'(("OSMODE") ("CECOLOR"))`) - wird ebenfalls mit `--method`-Logik instrumentiert, sofern sich ihr `(defun ...)` in einem der durchsuchten Verzeichnisse findet. AutoLISP-/BricsCAD-Builtins (`princ`, `command`, `strcat`, `rtos`, `entmake`, `vla-*`, ...) haben dort naturgemaess kein `defun` und werden dadurch automatisch **nicht** angefasst - es gibt keine Builtin-Blacklist zu pflegen. Die `ssg_dbg.lsp`-Funktionen selbst (`dbgf`, `dbg`, `dbgp`, `dbgmsg`, `dbgreturn`, `dbgopen`, `dbgclose`, `dbgflush`, `dbgon`, `dbgoff` und ihre internen `dbg-*`-Helfer) sind fest ausgeschlossen, damit eine bereits instrumentierte Funktion nicht dazu fuehrt, dass das Debug-Framework sich selbst instrumentiert. Bereits instrumentierte Funktionen werden uebersprungen (siehe [Idempotenz](#idempotenz)), ihr Rumpf wird aber trotzdem nach weiteren, noch nicht instrumentierten Aufrufen durchsucht - die Rekursion bricht dadurch nicht an einer schon bearbeiteten Stelle ab. ### --add-open Fuegt in der angegebenen Methode (typischerweise ein `c:BEFEHL`-Kommando, das einen ganzen Testlauf umspannt) ein: ```lisp (dbgopen "" "") ``` als erste Rumpf-Form, sowie ```lisp (dbgclose) ``` vor **jedem** `(exit)`-Aufruf im Rumpf (auch verschachtelt) und zusaetzlich am Ende des Rumpfs - ausser die letzte Rumpf-Form ist bereits selbst ein `(exit)` (dann waere ein zweites `dbgclose` ohnehin unerreichbarer Code). `--add-open DATEI METHODE` ist unabhaengig von `--method`/`--recursive` nutzbar und mehrfach angebbar; alle drei Mechanismen lassen sich in einem Aufruf kombinieren. ## Schalter | Schalter | Beschreibung | |---|---| | `datei` (Pflicht, Position 1) | Anker-`.lsp`-Datei; ihr Verzeichnis wird immer mitdurchsucht | | `--method NAME` | Funktion mit `dbgf`/`dbg`/`dbgreturn` instrumentieren (mehrfach angebbar) | | `--recursive` | Auch alle im Rumpf aufgerufenen projekteigenen Funktionen instrumentieren | | `--search-dir DIR` | Weiteres Verzeichnis nach `.lsp`-Dateien durchsuchen (mehrfach angebbar). Default: `Lisp/` und das Verzeichnis von `datei` | | `--max-depth N` | Maximale Rekursionstiefe fuer `--recursive` (Default: `3`) | | `--exclude NAME` | Funktionsname von `--recursive` ausschliessen (mehrfach angebbar) | | `--add-open DATEI METHODE` | `dbgopen`/`dbgclose` in `METHODE` (aus `DATEI`) einfuegen (mehrfach angebbar) | | `--dbg-file NAME` | Dateiname fuer `(dbgopen ...)`. Default: aus dem `--add-open`-Methodennamen abgeleitet (`c:TEST_MUBEA` -> `test_mubea.dbg`) | | `--dbg-envvar NAME` | Umgebungsvariable fuer `(dbgopen ...)` (Default: `DXFM_LOG`) | | `--force` | Auch instrumentieren, wenn bereits `(dbgf ...)`/`(dbgopen ...)` vorhanden zu sein scheint | | `--dry-run` | Nur ein Diff anzeigen, keine Dateien schreiben | ## Typischer Ablauf 1. **Immer zuerst `--dry-run`** laufen lassen und das Diff pruefen (mehrere Dateien koennen betroffen sein, siehe `--recursive`). 2. Ohne `--dry-run` erneut aufrufen - die Dateien werden direkt (in-place) geschrieben. 3. In BricsCAD `(load ...)` neu laden bzw. den Testlauf starten. 4. Die `.dbg`-Datei (per `--add-open` geoeffnet, Pfad = `%DXFM_LOG%\<--dbg-file>`) auswerten. 5. Da die Dateien in-place geschrieben werden und ueber Git versioniert sind: nach dem Debuggen die Debug-Aufrufe entweder manuell entfernen oder die Datei(en) per `git checkout -- ` verwerfen (das Werkzeug selbst hat keinen "--remove"-Schalter). ## Beispiele Eine einzelne Funktion instrumentieren: ``` bin\dbg2lsp.bat tests\test_mubea.lsp --method mubea:build-separator-one --dry-run ``` Eine Funktion UND alles, was sie aufruft (bis Tiefe 3, Default): ``` bin\dbg2lsp.bat tests\test_mubea.lsp --method mubea:build-kreisel --recursive --dry-run ``` Mehrere Einstiegspunkte in einem Lauf, plus Oeffnen/Schliessen der Debug-Datei im umgebenden Testbefehl - das entspricht genau der Instrumentierung, die fuer den urspruenglichen Scanner-Bug in `TEST_MUBEA` von Hand gemacht wurde: ``` bin\dbg2lsp.bat tests\test_mubea.lsp ^ --method mubea:build-kreisel ^ --method mubea:build-vario-one ^ --method mubea:build-gf-one ^ --method mubea:build-separator-one ^ --recursive ^ --add-open tests\test_mubea.lsp c:TEST_MUBEA ``` Bestimmte generische Helfer von der Rekursion ausschliessen (z.B. um `ssg-start`/`ssg-end` nicht mit anzufassen): ``` bin\dbg2lsp.bat tests\test_mubea.lsp --method mubea:build-kreisel --recursive ^ --exclude ssg-start --exclude ssg-end ``` ## Funktionsweise / Aufloesung - `datei` wird zuerst relativ zum aktuellen Arbeitsverzeichnis, sonst relativ zur Projektwurzel (erkannt an `.git/` bzw. `Lisp/`, ausgehend von `datei` nach oben gesucht) aufgeloest. - Durchsucht werden: das Verzeichnis von `datei`, `Lisp/` (relativ zur Projektwurzel), jedes `--search-dir` sowie das Verzeichnis jeder `--add-open`-Datei - jeweils rekursiv nach `*.lsp`. - Aus all diesen Dateien wird EIN Index `Funktionsname -> (defun ...)` aufgebaut (case-insensitiv, wie AutoLISP-Symbole zur Laufzeit). `--method`/`--add-open` muessen daher nicht in `datei` selbst stehen, sondern werden ueberall gefunden. - Klammer-/String-/Kommentar-Erkennung ist zeichenweise implementiert (kein vollstaendiger Lisp-Reader) - genuegt aber, um Top-Level-`(defun ...)`-Bloecke, ihre Parameterliste und die letzte Rumpf-Form zuverlaessig zu erkennen, auch bei mehrzeiligen Parameterlisten mit Locals nach `/`. - Alle Aenderungen werden zunaechst als Liste von reinen Text-Einfuegungen gesammelt (keine Loeschungen) und erst am Ende je Datei angewandt - Positionen bleiben dadurch unabhaengig von der Bearbeitungsreihenfolge gueltig. ## Grenzen - **Nur die letzte Rumpf-Form wird zu `dbgreturn`.** Fruehe `(exit)`-Ausstiege MITTEN im Rumpf werden von `--method` nicht mit einem eigenen `dbgreturn` versehen (nur `--add-open` behandelt `(exit)`-Stellen explizit, dort aber nur mit `dbgclose`, nicht mit einem geloggten Rueckgabewert). - **Kein "--remove".** Rueckbau erfolgt manuell oder per `git checkout -- `. - **`--recursive` kann viele Dateien anfassen** - projekteigene Helfer wie `ssg-start`/`ssg-val`/`ssg-attrib-merge` werden mitinstrumentiert, sobald sie im Aufrufgraphen auftauchen. `--max-depth` und `--exclude` begrenzen das gezielt; ohne `--dry-run`-Kontrolle vorher nicht blind auf grosse Funktionen mit hoher `--max-depth` loslassen. - **Mehrfache Definitionen desselben Namens** in unterschiedlichen Dateien: es gewinnt der erste beim Durchsuchen gefundene (Dateireihenfolge nicht garantiert sortiert-stabil ueber Verzeichnisgrenzen) - in dieser Codebasis kommt das ueblicherweise nicht vor. ## Idempotenz Vor dem Einfuegen prueft das Werkzeug, ob die erste Rumpf-Form bereits `(dbgf ...)` (fuer `--method`) bzw. `(dbgopen ...)` (fuer `--add-open`) ist, und ueberspringt die Funktion in dem Fall mit einer `[skip]`-Meldung. Mit `--force` wird trotzdem erneut eingefuegt (fuehrt bei wiederholtem `--force`-Aufruf zu doppelten `dbgf`/`dbg`-Zeilen - in dem Fall vorher besser die Datei zuruecksetzen).