Obtenga la función para una línea específica en un archivo fuente C [cerrado]

¿Hay alguna herramienta que pueda usar para averiguar el nombre de la función a la que pertenece un número de línea fuente específico?

Archivo de ejemplo:

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

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

Para la línea 4, return B1;la respuesta debería ser bar.

Uso la sintaxis fuente C99 . El código fuente solo se puede compilar con GCC debido a sus dependencias.

C99 es una especificación para C. Ansi C sería C89. Pero hay, por ejemplo, cosas como K&R C, bastante importantes cuando se trata de analizar el archivo fuente para encontrar los nombres de las funciones.

La pregunta se cerró como fuera de tema en SO .

¿Está bien una herramienta de línea de comandos? ¿Para qué sistema operativo?
¿Quiere que la herramienta admita cosas que la mayoría de la gente no usa, como K&R C, o es suficiente si funciona con un código que respeta las convenciones de codificación modernas y decentes? ¿Tiene que comprender las definiciones del preprocesador (por ejemplo, si la línea de definición de la función está en bloques #ifdef), o está bien un análisis textual simple? ¿Tiene que comprender presentaciones inusuales como una definición de función prevista?
Hmph, acabo de darme cuenta de que esto está cerrado. La pregunta de OP me parece perfectamente clara (ver mi respuesta "perfectamente clara"). No cumple con los requisitos de SR de tener claro qué restricciones de plataforma para la herramienta, etc.

Respuestas (1)

Nuestro kit de herramientas de reingeniería de software DMS con su C Front End podría usarse fácilmente para hacer esto.

DMS analiza y crea AST para un idioma definido para él. El extremo frontal de C define una variedad de dialectos de C para DMS, incluido C99. El resultado de aplicar C Front-end con DMS a un archivo C (completo con directivas/expansión de preprocesador, etc.) es un AST con cada nodo marcado en cuanto a su tipo de regla gramatical, con archivo fuente, línea y columna.

Dado un árbol de este tipo, se puede usar la interfaz AST de DMS para comenzar en la raíz, recorrer el árbol hasta encontrar un nodo con el número de línea 4. Bajo la suposición de que está dentro de una función (puede que no lo esté), puede subir fácilmente por el árbol hasta un nodo que es una declaración de función, y luego bajar un nodo hasta la identificación de la función, y luego imprimir la cadena asociada con ese nodo .

El código para lograr con DMS se ve así:

(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 utiliza un lenguaje de programación paralelo estilo lisp-syntax llamado PARLANSE para su lenguaje de metaprogramación. Creo que lo que hace lo anterior es bastante claro. He dejado de lado toda la comprobación de errores (aunque las excepciones de PARLANSE harán la mayor parte por el programador) por motivos explicativos.

DMS es único en el sentido de que no necesariamente tiene que expandir todas las directivas del preprocesador para analizar el texto. El extremo frontal C tiene un modo en el que las directivas PP "bien estructuradas" simplemente se analizan y retienen en el árbol; no puede manejar condicionales PP que abarquen no terminales C. Todavía puede encontrar el nombre de la función de la misma manera, pero es posible que deba preocuparse de que el identificador que se encuentra en la declaración de la función sea en realidad una macro o que esté envuelto en un condicional. El frente C tiene otro modo experimental (creemos que funciona, pero aún lo estamos comprobando) en el que las directivas PP se pueden analizar a pesar de la ubicación arbitraria. Aún debe preocuparse por las directivas PP que afectan el nombre de la función. Pero estos dos modos permiten manipular muchos programas C sin tener que configurar el preprocesador correctamente o sin tener que configurarlo.

Estoy seguro de que puede configurar Clang para hacer esta extracción de número de línea; AFAIK, solo puede hacer esto haciendo un preprocesamiento completo. Clang está diseñado para usarse en tareas como esta, pero principalmente solo para C y C++.

Probablemente puedas hacer esto con GCC, pero GCC no fue diseñado para ser útil, por lo que el esfuerzo para hacer esto probablemente sea mucho más de lo que esperas.

El front-end de EDG puede analizar C, y estoy seguro de que hará algo similar con él después de expandir las declaraciones del preprocesador.

No tengo mucha experiencia con los últimos 3, aunque he estado siguiendo su evolución literalmente durante décadas.

Lo siento, pero me rendí en stackexchange. Los mods aquí paralizaron mi pregunta hasta el punto en que ya no tiene sentido y luego bloquearon la pregunta porque no está claro lo que pregunté.
Pero gracias por tu respuesta tan detallada.
@ConchúrNavid: SO es absolutamente irrazonable en este tipo de preguntas. SR tiene la intención de alentarlo, pero están molestos por obtener suficientes requisitos detallados para que las respuestas puedan juzgarse claramente. Creo que si ajusta ligeramente el texto, se elimina el "en espera".