Holen Sie sich die Funktion für eine bestimmte Zeile in einer C-Quelldatei [geschlossen]

Gibt es ein Tool, mit dem ich den Funktionsnamen herausfinden kann, zu dem eine bestimmte Quellzeilennummer gehört?

Beispieldatei:

static enum foo bar(int c)
{
    if (c < 30)
        return B1;
    else
        return B2;
}

static enum foo somethingelse(void)
{
    return B3;
}

Für Zeile 4 return B1;sollte die Antwort lauten bar.

Ich verwende C99- Quellsyntax. Der Quellcode kann aufgrund seiner Abhängigkeiten nur mit GCC kompiliert werden.

C99 ist eine Spezifikation für C. Ansi C wäre C89. Aber es gibt zum Beispiel Dinge wie K&R C - ziemlich wichtig, wenn es darum geht, die Quelldatei zu parsen, um die Funktionsnamen zu finden.

Die Frage wurde als Off-Topic auf SO geschlossen .

Ist ein Befehlszeilentool in Ordnung? Für welches Betriebssystem?
Möchten Sie, dass das Tool Dinge unterstützt, die die meisten Menschen nicht verwenden, wie z. B. K&R C, oder reicht es aus, wenn es mit Code funktioniert, der moderne, anständige Codierungskonventionen respektiert? Muss es Präprozessordefinitionen verstehen (z. B. wenn die Funktionsdefinitionszeile in #ifdef-Blöcken steht) oder ist eine einfache Textanalyse in Ordnung? Muss es ungewöhnliche Darstellungen wie eine beabsichtigte Funktionsdefinition verstehen?
Hmpf, habe gerade gesehen, dass hier geschlossen ist. Die Frage von OP scheint mir vollkommen klar zu sein (siehe meine "vollkommen klare" Antwort). Es scheitert an den SR-Anforderungen, klar zu machen, welche Plattformeinschränkungen für das Tool usw.

Antworten (1)

Unser DMS Software Reengineering Toolkit mit seinem C-Frontend könnte dazu problemlos verwendet werden.

DMS analysiert und erstellt ASTs für eine ihm definierte Sprache. Das C-Frontend definiert eine Vielzahl von C-Dialekten für DMS, einschließlich C99. Das Ergebnis der Anwendung des C-Frontends mit DMS auf eine C-Datei (komplett mit Präprozessordirektiven/Erweiterung usw.) ist ein AST, bei dem jeder Knoten mit seinem Grammatikregeltyp versehen ist, mit Quelldatei, Zeile und Spalte.

Bei einem solchen Baum kann man das ASTInterface von DMS verwenden, um an der Wurzel zu beginnen und über den Baum zu gehen, bis ein Knoten mit der Zeilennummer 4 gefunden wird. Unter der Annahme, dass es sich innerhalb einer Funktion befindet (was möglicherweise nicht der Fall ist), können Sie den Baum problemlos zu einem Knoten hinaufgehen, der eine Funktionsdeklaration ist, und dann einen Knoten hinunter zur Funktions-ID und dann die diesem Knoten zugeordnete Zeichenfolge drucken .

Der mit DMS auszuführende Code sieht folgendermaßen aus:

(define FindFunctionName
   (lambda (function natural [FileName (reference string)] [target_line_number natural])
   (local (;; (= [my_tree AST:Node] (C~GCC4:ParserComponent:Parse FileName)
               (= [current_node AST:Node] (AST:FindInSubtree my_tree
                      (lambda (function boolean AST:Node)
                           (== (AST:GetLineNumber ?) target_line_number)
                      )lambda )=
            );;
       (= current_node (AST:FindParent current_node
                          (lambda (function boolean AST:Node)
                              (== (AST:GetNodeType ?)
                                  C~GCC4:ParserComponent:TokenNumber:function_declaration)
                          )lambda )=
       (return (AST:GetStringLiteral (AST:GetNthChild current_node 2)) ; id node under function_declaration
    )local

DMS verwendet eine parallele Programmiersprache im Lisp-Syntax-Stil namens PARLANSE für seine Metaprogrammiersprache. Ich denke, was das obige tut, ist ziemlich klar. Ich habe die gesamte Fehlerprüfung (obwohl PARLANSE-Ausnahmen das meiste davon für den Programmierer erledigen) aus erklärenden Gründen weggelassen.

DMS ist insofern einzigartig, als Sie nicht unbedingt alle Präprozessordirektiven erweitern müssen, um den Text zu parsen. Das C-Frontend hat einen Modus, in dem "gut strukturierte" PP-Anweisungen einfach geparst und im Baum beibehalten werden; Es kann nicht mit PP-Bedingungen umgehen, die C-Nichtterminale umfassen. Sie können den Funktionsnamen immer noch auf die gleiche Weise finden, aber Sie müssen sich möglicherweise Sorgen machen, dass der in der Funktionsdeklaration gefundene Bezeichner tatsächlich ein Makro ist oder in eine Bedingung eingeschlossen sein könnte. Die C-Front hat einen weiteren experimentellen Modus (wir glauben, dass er funktioniert, prüfen es aber noch), in dem PP-Direktiven trotz willkürlicher Platzierung geparst werden können. Sie müssen sich immer noch um PP-Direktiven kümmern, die sich auf den Funktionsnamen auswirken. Aber diese beiden Modi erlauben es, viele C-Programme zu manipulieren, ohne den Präprozessor richtig oder überhaupt konfigurieren zu müssen.

Ich bin sicher, Sie können Clang so konfigurieren, dass es diese Zeilennummer extrahiert. AFAIK, es kann dies nur durch eine vollständige Vorverarbeitung tun. Clang wurde für solche Aufgaben entwickelt, aber hauptsächlich nur für C und C++.

Sie können dies wahrscheinlich mit GCC tun, aber GCC wurde nicht entwickelt, um hilfreich zu sein, daher ist der Aufwand dafür wahrscheinlich viel größer, als Sie erwarten würden.

Das EDG-Frontend kann C parsen, und ich bin sicher, dass Sie etwas Ähnliches damit machen, nachdem Sie die Präprozessordeklarationen erweitert haben.

Ich habe nicht viel Erfahrung mit den letzten 3, obwohl ich ihre Entwicklung buchstäblich Jahrzehnte lang verfolgt habe.

Tut mir leid, aber ich habe Stackexchange aufgegeben. Die Mods hier haben meine Frage bis zu einem Punkt verkrüppelt, an dem sie keinen Sinn mehr macht, und dann die Frage blockiert, weil nicht klar ist, was ich gefragt habe.
Aber danke für deine sehr ausführliche Antwort
@ConchúrNavid: SO ist bei dieser Art von Frage völlig unvernünftig. SR soll dazu ermutigen, aber sie sind launisch, wenn es darum geht, genügend detaillierte Anforderungen zu erhalten, damit die Antworten klar beurteilt werden können. Ich denke, wenn Sie den Text leicht anpassen, wird das "in der Warteschleife" entfernt.