¿Cómo se suelen analizar los comentarios?

31

¿Cómo se tratan generalmente los comentarios en lenguajes de programación y marcado? Estoy escribiendo un analizador para un lenguaje de marcado personalizado y quiero seguir el principio de menor sorpresa , así que estoy tratando de determinar la convención general.

Por ejemplo, ¿debería un comentario incrustado dentro de un token 'interferir' con el token o no? En general, es algo como:

Sys/* comment */tem.out.println()

¿válido?

Además, si el lenguaje es sensible a las nuevas líneas y el comentario abarca la nueva línea, ¿debería considerarse o no la nueva línea?

stuff stuff /* this is comment
this is still comment */more stuff 

ser tratado como

stuff stuff more stuff

o

stuff stuff
more stuff

?

Sé lo que hacen algunos idiomas específicos, ni estoy buscando opiniones, pero estoy buscando si hay o no: ¿hay un consenso general sobre lo que generalmente se espera con un marcado en lo que respecta a tokens y nuevas líneas?


Mi contexto particular es un marcado tipo wiki.

Trineo
fuente
¿Existe la nueva línea dentro del comentario? ¿Por qué sería tratado de manera diferente a cualquier otro personaje en el comentario?
1
@Snowman existe esa perspectiva, pero por otro lado, si el token 'x' tiene un significado especial si es el primer token en la línea y parece ser el primer token en la línea tanto para la persona que mira la fuente como para el analizador de lectura línea por línea. Parece un dilema, así que hice la pregunta.
Trineo
44
Hace un tiempo necesitaba hacer esto exactamente según las especificaciones y descubrí que los documentos de gcc son un excelente recurso. Hay algunos casos extraños que quizás no hayas considerado.
Karl Bielefeldt

Respuestas:

40

Por lo general, los comentarios se escanean (y descartan) como parte del proceso de tokenización, pero antes del análisis. Un comentario funciona como un separador de token incluso en ausencia de espacios en blanco a su alrededor.

Como señala, la especificación C establece explícitamente que los comentarios se reemplazan por un solo espacio. Sin embargo, es solo una jerga de especificaciones, ya que un analizador del mundo real no reemplazará nada, sino que simplemente escaneará y descartará un comentario de la misma manera que escanea y descarta los caracteres de espacios en blanco. Pero explica de manera simple que un comentario separa los tokens de la misma manera que lo haría un espacio.

El contenido de los comentarios se ignora, por lo que los saltos de línea dentro de los comentarios multilínea no tienen ningún efecto. Los lenguajes sensibles a los saltos de línea (Python y Visual Basic) generalmente no tienen comentarios de varias líneas, pero JavaScript es una excepción. Por ejemplo:

return /*
       */ 17

Es equivalente a

return 17

no

return
17

Los comentarios de una sola línea conservan el salto de línea, es decir

return // single line comment
    17

es equivalente a

return
17

no

return 17

Dado que los comentarios se escanean pero no se analizan, tienden a no anidarse. Asi que

 /*  /* nested comment */ */

es un error de sintaxis, ya que el comentario se abre por el primero /*y se cierra por el primero*/

JacquesB
fuente
3
En la mayoría de los idiomas, los comentarios en línea ( /* like this */) se consideran iguales a un espacio en blanco y los comentarios terminados en EOL ( // like this) a una línea en blanco.
9000
@JacquesB, así que estoy pensando en tratar los comentarios como reemplazados en su totalidad de la fuente como un espacio de ancho cero , que parece ser equivalente a lo que estás sugiriendo.
Trineo
1
@artb un espacio ordinario debería funcionar bien, y se encuentra en la página de códigos ASCII.
John Dvorak
@JanDvorak un espacio afectará la apariencia y elimina la comprensión y está más cerca de la semántica de "un comentario no está realmente allí". La salida de representación principal será HTML, por lo que en mi caso ASCII no es tan problemático ya que los navegadores admiten Unicode. Dicho esto, creo que el estándar C exige que los comentarios se reemplacen con un solo espacio.
Trineo
1
Algunos idiomas, especialmente Racket, tienen comentarios anidados de varias líneas: (define x #| this is #| a sub-comment |# the main comment |# 3) xrendimientos 3.
wchargin
9

Para responder la pregunta:

¿Existe un consenso general sobre lo que generalmente se espera de un recargo?

Diría que ninguno esperaría que un comentario incrustado dentro de un token sea legal.

Como regla general, los comentarios deben tratarse de la misma manera que los espacios en blanco. Cualquier lugar que sea válido para tener espacios en blanco extraños también debería tener un comentario incrustado. La única excepción serían las cadenas:

trace("Hello /*world*/") // should print Hello /*world*/

Sería bastante extraño apoyar los comentarios dentro de las cadenas, ¡y haría que escapar de ellos sea tedioso!

Connor Clark
fuente
2
Nunca pensé en cuerdas, ese es un buen caso extremo. Mi pensamiento actual era hacer una expresión regular simple entre el comienzo y el final del comentario y reemplazarlo con un solo espacio. Eso habría disparado tu caso.
Trineo
3
+1 por ese bit sobre las cadenas de escape. Aunque, en su ejemplo, generalmente esperaría que se imprima en Hello /* world*/!lugar de suprimir los delimitadores de comentarios. Además, ¡bienvenidos a los programadores!
8bittree
1
Gracias 8bittree! Y eso es totalmente lo que quise decir. Curiosamente, también necesito escapar del ** en mi respuesta ...
Connor Clark
2
@ArtB en general, "analizar por sustitución" se vuelve muy complicado en el futuro con casos extremos e interacción con otras características, y es mejor evitarlo desde el principio.
hobbs
7

En los idiomas insensibles a espacios en blanco, los caracteres ignorados (es decir, espacios en blanco o aquellos que forman parte de un comentario) delimitan los tokens.

Entonces, por ejemplo, Sys temson dos tokens, mientras que Systemes uno. La utilidad de esto podría ser más evidente si compara new Foo()y newFoo()uno de ellos construirá una instancia Foomientras que el otro llama newFoo.

Los comentarios pueden desempeñar el mismo papel que una serie de espacios en blanco, por ejemplo, new/**/Foo()funciona igual que new Foo(). Por supuesto, esto puede ser más complejo, por ejemplo, new /**/ /**/ Foo()o no.

Técnicamente, debería ser posible permitir comentarios dentro de los identificadores, pero dudo que sea particularmente práctico.

Ahora, ¿qué pasa con los idiomas sensibles al espacio en blanco?

Python viene a mi mente y tiene una respuesta muy simple: no hay comentarios de bloque. Se empieza con un comentario #y luego el analizador funciona exactamente como si el resto de la línea no existía, pero eran sólo un salto de línea en su lugar.

En contraste con eso, jade permite comentarios de bloque , donde el bloque termina cuando vuelve al mismo nivel de sangría. Ejemplo:

body
  //-
    As much text as you want
    can go here.
  p this is no longer part of the comment

Así que en este ámbito, yo no diría que se podría decir cómo las cosas están por lo general manejan. Lo que parece ser algo en común es que un comentario siempre termina con un final de línea, lo que significa que todos los comentarios actúan exactamente igual que las nuevas líneas.

back2dos
fuente
Hmm, la nueva línea es el problema real ya que estamos utilizando la sintaxis HTML \ XML para comentarios, por lo que será de varias líneas.
Trineo
3
@ArtB Si está utilizando la sintaxis HTML / XML, puede ser conveniente simplemente usar su comportamiento.
8bittree
1
@ 8bittree tiene sentido, debería haber pensado en eso. Dejaré la pregunta tal como está, ya que será más útil de esta manera.
Trineo
3

En el pasado, convertí los comentarios en un solo token como parte del análisis léxico. Lo mismo ocurre con las cuerdas. A partir de ahí, la vida es fácil.

En el caso específico del último analizador que construí, se pasa una regla de escape a la rutina de análisis de nivel superior. La regla de escape se usa para manejar tokens como tokens de comentarios en línea con la gramática central. En general, estos tokens fueron descartados.

Una consecuencia de hacerlo de esta manera es que el ejemplo que publicó con un comentario en el medio de un identificador, el identificador no sería un solo identificador; este es el comportamiento esperado en todos los idiomas (de memoria) con los que he trabajado .

El caso de un comentario dentro de una cadena debe ser manejado implícitamente por el análisis léxico. Las reglas para manejar una cadena no tienen interés en los comentarios y, como tal, el comentario se trata como el contenido de la cadena. Lo mismo se aplica a una cadena (o literal citado) dentro de un comentario: la cadena es parte de un comentario, que es explícitamente un token único; Las reglas para procesar un comentario no tienen interés en las cadenas.

Espero que tenga sentido / ayuda.

usuario202190
fuente
Entonces, si tiene un código como console.log(/*a comment containing "quotes" is possible*/ "and a string containing /*slash-star, star-slash*/ is possible"), donde hay comillas en un comentario y sintaxis de comentario en una cadena, ¿cómo sabría el lexer tokenizarlo correctamente? ¿Puede editar su respuesta, proporcionando una descripción general de esos casos?
chharvey
1

Depende de qué propósito tenga su analizador. Si escribe un analizador para construir un árbol de análisis para la compilación, un comentario no tiene valor semántico además de los tokens potencialmente separados (por ejemplo, método / comentario / (/ comentario /)). En este caso, se trata como espacios.

Si su analizador es parte de un transpilador que traduce un idioma de origen a otro idioma de origen o si su analizador es un preprocesador que toma una unidad de compilación en un idioma de origen, analiza, modifica y escribe la versión modificada en el mismo idioma de origen, comentarios como cualquier otra cosa se vuelve muy importante.

Además, si tiene metainformación en los comentarios y le interesan especialmente los comentarios como cuando se genera documentación API como lo hace JavaDoc, los comentarios de repente son muy importantes.

Aquí los comentarios a menudo se adjuntan a los tokens en sí. Si encuentra un comentario, lo adjunta para que sea un comentario de un token. Como un token puede tener múltiples tokens antes y después, nuevamente depende del propósito de cómo manejar esos comentarios.

La idea de anotar tokens sin comentarios con comentarios es eliminar los comentarios de la gramática por completo.

Una vez que tiene el árbol de análisis, algunos AST comienzan a desempaquetar los comentarios que representan cada token por su propio elemento AST, pero se adjuntan a otro elemento AST junto a la relación de contención habitual. Una buena idea es verificar todas las implementaciones de analizador / AST para los idiomas de origen disponibles en IDE de código abierto.

Una muy buena implementación es la infraestructura del compilador Eclipse para el lenguaje Java. Conservan los comentarios durante la tokenización y representan comentarios dentro del AST, por lo que recuerdo. Además, esta implementación de analizador / AST conserva el formato.

Martin Kersten
fuente