Comment les commentaires sont-ils généralement analysés?

31

Comment les commentaires sont-ils généralement traités dans les langages de programmation et le balisage? J'écris un analyseur pour un langage de balisage personnalisé et je veux suivre le principe de la moindre surprise , donc j'essaie de déterminer la convention générale.

Par exemple, un commentaire incorporé dans un jeton devrait-il «interférer» ou non avec le jeton? En général, c'est quelque chose comme:

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

valide?

De plus, si la langue est sensible aux nouvelles lignes et que le commentaire couvre la nouvelle ligne, la nouvelle ligne doit-elle être prise en compte ou non?

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

être traité comme

stuff stuff more stuff

ou

stuff stuff
more stuff

?

Je sais ce que font quelques langues spécifiques, je ne cherche pas d'opinions, mais je cherche si oui ou non: y a-t-il un consensus général sur ce que l'on attend généralement d'une majoration en ce qui concerne les jetons et les nouvelles lignes?


Mon contexte particulier est un balisage de type wiki.

Traîneau
la source
La nouvelle ligne existe-t-elle à l'intérieur du commentaire? Pourquoi serait-il traité différemment de tout autre personnage dans le commentaire?
1
@Snowman, il y a cette perspective, mais d'un autre côté, si le jeton 'x' a une signification particulière s'il s'agit du premier jeton sur la ligne et qu'il semble être le premier jeton sur la ligne à la fois pour la personne qui regarde la source et pour le analyseur de lecture ligne par ligne. Cela ressemble à un dilemme, alors j'ai posé la question.
Traîneau du
4
J'ai dû faire cela exactement selon les spécifications il y a quelque temps et j'ai trouvé que les documents de gcc étaient une excellente ressource. Il y a des cas étranges que vous n'avez peut-être pas envisagés.
Karl Bielefeldt

Réponses:

40

Habituellement, les commentaires sont analysés (et supprimés) dans le cadre du processus de tokenisation, mais avant l'analyse. Un commentaire fonctionne comme un séparateur de jetons, même en l'absence d'espaces autour.

Comme vous le faites remarquer, la spécification C indique explicitement que les commentaires sont remplacés par un seul espace. Cependant, ce n'est que du jargon de spécification, car un analyseur réel ne remplacera rien, mais analysera et supprimera un commentaire de la même manière qu'il analyse et supprime les espaces. Mais cela explique de manière simple qu'un commentaire sépare les jetons de la même manière qu'un espace.

Le contenu des commentaires est ignoré, les sauts de ligne dans les commentaires multilignes n'ont donc aucun effet. Les langages sensibles aux sauts de ligne (Python et Visual Basic) n'ont généralement pas de commentaires multilignes, mais JavaScript est une exception. Par exemple:

return /*
       */ 17

Est équivalent à

return 17

ne pas

return
17

Les commentaires sur une seule ligne préservent le saut de ligne, c'est-à-dire

return // single line comment
    17

est équivalent à

return
17

ne pas

return 17

Étant donné que les commentaires sont analysés mais non analysés, ils ont tendance à ne pas s'imbriquer. Alors

 /*  /* nested comment */ */

est une erreur de syntaxe, car le commentaire est ouvert par le premier /*et fermé par le premier*/

JacquesB
la source
3
Dans la plupart des langues, les commentaires en ligne ( /* like this */) sont considérés comme égaux à un seul espace blanc et les commentaires terminés par EOL ( // like this) à une ligne vierge.
9000
@JacquesB donc je pense à traiter les commentaires comme étant remplacés dans leur intégralité à partir de la source comme un espace de largeur nulle , ce qui semble être équivalent à ce que vous proposez.
Traîneau
1
@artb un espace ordinaire devrait fonctionner très bien, et se trouve dans la page de code ASCII.
John Dvorak
@JanDvorak un espace affectera l'apparence et enlèvera la compréhension et est plus proche de la sémantique "un commentaire n'est pas vraiment là". La sortie de rendu principale sera HTML, donc dans mon cas, ASCII n'est pas aussi problématique que les navigateurs prennent en charge Unicode. Cela dit, je crois que la norme C exige que les commentaires soient remplacés par un seul espace.
Traîneau
1
Certaines langues, notamment Racket, ont des commentaires multilignes imbriqués: les (define x #| this is #| a sub-comment |# the main comment |# 3) xrendements 3.
wchargin
9

Pour répondre à la question:

y a-t-il un consensus général sur ce que l'on attend généralement d'une majoration?

Je dirais que personne ne s'attendrait à ce qu'un commentaire intégré à l'intérieur d'un jeton soit légal.

En règle générale, les commentaires doivent être traités de la même manière que les espaces blancs. N'importe quel endroit qui serait valide pour avoir des espaces étrangers devrait également être autorisé à avoir un commentaire intégré. La seule exception serait les chaînes:

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

Il serait assez étrange de supporter les commentaires à l'intérieur des chaînes, et cela rendrait leur échappatoire fastidieux!

Connor Clark
la source
2
Je n'ai jamais pensé aux cordes, c'est un bon cas de bord. Ma pensée actuelle consistait à faire une regex simple entre le début et la fin du commentaire et à le remplacer par un seul espace. Cela aurait déclenché votre cas.
Traîneau du
3
+1 pour ce bit sur l'échappement des chaînes. Bien que, dans votre exemple, je m'attende généralement à ce qu'il s'imprime au Hello /* world*/!lieu de supprimer les délimiteurs de commentaire. Bienvenue également aux programmeurs!
8bittree
1
Merci 8bittree! Et c'est totalement ce que je voulais dire. Curieusement, je dois aussi échapper à la ** dans ma réponse ....
Connor Clark
2
@ArtB en général, "l'analyse par substitution" devient très délicat sur la route avec des cas marginaux et l'interaction avec d'autres fonctionnalités, et il est préférable d'éviter dès le début.
hobbs
7

Dans les langues insensibles aux espaces, les caractères ignorés (c'est-à-dire les espaces ou ceux qui font partie d'un commentaire) délimitent les jetons.

Ainsi, par exemple, il Sys temy a deux jetons, alors qu'il Systemy en a un. L'utilité de ceci pourrait être plus évidente si vous comparez new Foo()et newFoo()dont l'un construira une instance de Footandis que l'autre appelle newFoo.

Les commentaires peuvent jouer le même rôle qu'une série d'espaces blancs, par exemple new/**/Foo()fonctionne de la même manière que new Foo(). Bien sûr, cela peut être plus complexe, par exemple new /**/ /**/ Foo()ou autre chose.

Techniquement, il devrait être possible d'autoriser les commentaires dans les identifiants, mais je doute que ce soit particulièrement pratique.

Maintenant, qu'en est-il des langues sensibles aux espaces blancs?

Python vient à l'esprit et il a une réponse très simple: pas de commentaires de bloc. Vous commencez un commentaire avec #puis l'analyseur fonctionne exactement comme si le reste de la ligne n'existait pas, mais n'était qu'une nouvelle ligne à la place.

Contrairement à cela, le jade permet les commentaires de bloc , où le bloc se termine lorsque vous revenez au même niveau d'indentation. Exemple:

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

Donc, dans ce domaine, je ne dirais pas que vous pourriez dire comment les choses sont généralement traitées. Ce qui semble être un point commun, c'est qu'un commentaire se termine toujours par une fin de ligne, ce qui signifie que tous les commentaires agissent exactement de la même manière que les nouvelles lignes.

back2dos
la source
Hmm, la nouvelle ligne est le vrai problème car nous utilisons la syntaxe HTML \ XML pour les commentaires, elle sera donc multiligne.
Traîneau du
3
@ArtB Si vous utilisez la syntaxe HTML / XML, il peut être judicieux d'utiliser simplement leur comportement.
8bittree
1
@ 8bittree a du sens, aurait dû y penser. Je vais laisser la question telle quelle car elle sera plus utile de cette façon.
Traîneau du
3

Dans le passé, j'ai transformé les commentaires en un seul jeton dans le cadre de l'analyse lexicale. Il en va de même pour les cordes. De là, la vie est facile.

Dans le cas spécifique du dernier analyseur que j'ai construit, une règle d'échappement est transmise à la routine d'analyse de niveau supérieur. La règle d'échappement est utilisée pour gérer les jetons tels que les jetons de commentaire en ligne avec la grammaire principale. En général, ces jetons ont été jetés.

Une conséquence de cette façon de faire est que l'exemple que vous avez publié avec un commentaire au milieu d'un identifiant, l'identifiant ne serait pas un identifiant unique - c'est le comportement attendu dans toutes les langues (de mémoire) avec lesquelles j'ai travaillé .

Le cas d'un commentaire dans une chaîne doit être implicitement traité par l'analyse lexicale. Les règles pour gérer une chaîne n'ont aucun intérêt dans les commentaires, et en tant que tel, le commentaire est traité comme le contenu de la chaîne. Il en va de même pour une chaîne (ou littéral cité) dans un commentaire - la chaîne fait partie d'un commentaire, qui est explicitement un seul jeton; les règles de traitement d'un commentaire n'ont aucun intérêt pour les chaînes.

J'espère que cela a du sens / aide.

user202190
la source
Donc, si vous avez du code tel que console.log(/*a comment containing "quotes" is possible*/ "and a string containing /*slash-star, star-slash*/ is possible"), où il y a des guillemets dans un commentaire et une syntaxe de commentaire dans une chaîne, comment le lexeur saurait-il le tokeniser correctement? Pouvez-vous modifier votre réponse en fournissant une description générale de ces cas?
chharvey
1

Cela dépend du but de votre analyseur. Si vous écrivez un analyseur pour construire un arbre d'analyse pour la compilation, un commentaire n'a pas de valeur sémantique à côté des jetons de séparation potentiels (par exemple, méthode / commentaire / (/ commentaire /)). Dans ce cas, son traité comme des espaces.

Si votre analyseur fait partie d'un transpilateur traduisant une langue source dans une autre langue source ou si votre analyseur est un préprocesseur prenant une unité de compilation dans une langue source, l'analysant, la modifiant et réécrivant la version modifiée dans la même langue source, commentaires comme toute autre chose devient très important.

De plus, si vous avez des méta-informations dans les commentaires et que vous vous souciez particulièrement des commentaires comme lors de la génération de documentation API comme JavaDoc, les commentaires sont soudainement très importants.

Ici, les commentaires sont souvent attachés aux jetons eux-mêmes. Si vous trouvez un commentaire, vous le joignez pour être un commentaire d'un jeton. Puisqu'un jeton peut avoir plusieurs jetons avant et après, la manière de gérer ces commentaires dépend à nouveau de l'objectif.

L'idée d'annoter des jetons de non-commentaire avec des commentaires est de supprimer complètement les commentaires de la grammaire.

Une fois que vous avez l'arbre d'analyse, certains AST commencent à décompresser les commentaires représentant chaque jeton par son propre élément AST, mais étant attachés à un autre élément AST à côté de la relation contient habituelle. Une bonne idée est de vérifier toutes les implémentations de l'analyseur / AST pour les langages source disponibles dans l'IDE open-source.

Une très bonne implémentation est l'infrastructure du compilateur Eclipse pour le langage Java. Ils conservent les commentaires lors de la tokenisation et représentent des commentaires au sein de l'AST - pour autant que je m'en souvienne. De plus, cette implémentation de l'analyseur / AST préserve le formatage.

Martin Kersten
la source