Como os comentários geralmente são analisados?


31

Como os comentários são geralmente tratados em linguagens de programação e marcação? Estou escrevendo um analisador para alguma linguagem de marcação personalizada e quero seguir o princípio da menor surpresa , então estou tentando determinar a convenção geral.

Por exemplo, um comentário incorporado em um token 'interfere' com o token ou não? Geralmente, é algo como:

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

válido?

Além disso, se o idioma é sensível a novas linhas e o comentário abrange a nova linha, a nova linha deve ser considerada ou não?

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

ser tratado como

stuff stuff more stuff

ou

stuff stuff
more stuff

?

Sei o que alguns idiomas específicos fazem, nem procuro opiniões, mas procuro se há ou não: existe um consenso geral sobre o que geralmente é esperado por uma marcação em relação a tokens e novas linhas?


Meu contexto particular é uma marcação do tipo wiki.


A nova linha existe dentro do comentário? Por que isso seria tratado de maneira diferente de qualquer outro caractere no comentário?

1
@ Snowman, existe essa perspectiva, mas, por outro lado, se o token 'x' tiver um significado especial, se for o primeiro token na linha e parecer ser o primeiro token na linha para a pessoa que estiver olhando para a fonte e para o analisador de leitura linha por linha. Parece um dilema, então eu fiz a pergunta.
Sled

4
Eu precisava fazer isso exatamente com as especificações há um tempo atrás e achei os documentos do gcc um excelente recurso. Existem alguns casos de canto estranhos que você pode não ter considerado.
Karl Bielefeldt

Respostas:


40

Geralmente, os comentários são verificados (e descartados) como parte do processo de tokenização, mas antes da análise. Um comentário funciona como um separador de token, mesmo na ausência de espaço em branco ao seu redor.

Como você aponta, a especificação C afirma explicitamente que os comentários são substituídos por um único espaço. É apenas uma linguagem de especificação, já que um analisador do mundo real não substitui nada, mas apenas verifica e descarta um comentário da mesma maneira que verifica e descarta caracteres em branco. Mas explica de uma maneira simples que um comentário separa os tokens da mesma maneira que um espaço faria.

O conteúdo dos comentários é ignorado, portanto, as quebras de linha nos comentários de várias linhas não têm efeito. Os idiomas sensíveis a quebras de linha (Python e Visual Basic) geralmente não têm comentários de várias linhas, mas o JavaScript é uma exceção. Por exemplo:

return /*
       */ 17

É equivalente a

return 17

não

return
17

Comentários de linha única preservam a quebra de linha, ou seja,

return // single line comment
    17

é equivalente a

return
17

não

return 17

Como os comentários são verificados, mas não analisados, eles tendem a não se aninhar. tão

 /*  /* nested comment */ */

é um erro de sintaxe, pois o comentário é aberto pelo primeiro /*e fechado pelo primeiro*/


3
Na maioria dos idiomas, os comentários em linha ( /* like this */) são considerados iguais a um único espaço em branco e os comentários terminados em EOL ( // like this) a uma linha em branco.
9000

@ JacquesB, então estou pensando em tratar os comentários como sendo substituídos na íntegra da fonte como um espaço de largura zero , que parece ser equivalente ao que você está sugerindo.
Sled

1
@artb um espaço comum deve funcionar muito bem e está na página de código ASCII.
John Dvorak

@JanDvorak, um espaço afetará a aparência e removerá o entendimento e está mais próximo da semântica de "um comentário realmente não existe". A saída principal de renderização será HTML, portanto, no meu caso, o ASCII não é tão problemático quanto os navegadores suportam Unicode. Dito isto, acredito que o padrão C exige que os comentários sejam substituídos por um único espaço.
Sled

1
Alguns idiomas, principalmente o Racket, têm comentários aninhados em várias linhas: (define x #| this is #| a sub-comment |# the main comment |# 3) xyields 3.
wchargin

9

Para responder à pergunta:

existe um consenso geral sobre o que é geralmente esperado por uma marcação?

Eu diria que ninguém esperaria que um comentário incorporado dentro de um token fosse legal.

Como regra geral, os comentários devem ser tratados da mesma forma que os espaços em branco. Qualquer lugar que seria válido para ter espaços em branco externos também deve ter um comentário incorporado. A única exceção seria strings:

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

Seria bastante estranho apoiar comentários dentro de strings, e tornaria escapar deles tedioso!


2
Nunca pensei em cordas, esse é um bom caso. Meu pensamento atual era fazer uma regex simples entre o início e o fim do comentário e substituí-lo por um único espaço. Isso teria atrapalhado o seu caso.
Sled

3
+1 para um pouco sobre como escapar de strings. Embora, no seu exemplo, eu geralmente esperasse que fosse impresso, em Hello /* world*/!vez de suprimir os delimitadores de comentários. Bem-vindo também aos programadores!
8bittree

1
Graças 8bittree! E foi totalmente isso que eu quis dizer. Curiosamente, eu também preciso para escapar do ** na minha resposta ....
Connor Clark

2
@ArtB em geral, "analisar por substituição" fica muito complicado no futuro com casos extremos e interação com outros recursos, e é melhor evitar desde o início.
quer

7

Em idiomas não sensíveis a espaços em branco, caracteres ignorados (por exemplo, espaços em branco ou aqueles que fazem parte de um comentário) delimitam os tokens.

Por exemplo, Sys temsão dois tokens, enquanto Systemé um. A utilidade disso pode ser mais aparente se você comparar new Foo()e newFoo()um deles criará uma instância de Fooenquanto o outro chama newFoo.

Os comentários podem desempenhar o mesmo papel que uma série de espaços em branco, por exemplo, new/**/Foo()funciona da mesma forma que new Foo(). Claro que isso pode ser mais complexo, por exemplo, new /**/ /**/ Foo()ou outros enfeites.

Tecnicamente, deve ser possível permitir comentários dentro dos identificadores, mas duvido que seja particularmente prático.

Agora, o que dizer das linguagens sensíveis ao espaço em branco?

O Python vem à mente e tem uma resposta muito simples: sem comentários em bloco. Você inicia um comentário #e o analisador funciona exatamente como se o resto da linha não existisse, mas era apenas uma nova linha.

Em contraste com isso, o jade permite comentários em bloco , onde o bloco termina quando você volta ao mesmo nível de recuo. Exemplo:

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

Portanto, neste reino, eu não diria que você poderia dizer como as coisas são geralmente tratadas. O que parece ser uma semelhança, é que um comentário sempre termina com um final de linha, o que significa que todos os comentários agem exatamente da mesma forma que as novas linhas.


Hmm, a nova linha é o problema real, já que estamos usando a sintaxe HTML \ XML para comentários, portanto, será multilinhas.
Sled

3
@ArtB Se você estiver usando a sintaxe HTML / XML, pode ser recomendável simplesmente usar o comportamento deles.
8bittree

1
@ 8bittree faz sentido, deveria ter pensado nisso. Deixarei a questão como está, pois será mais útil dessa maneira.
Sled

3

No passado, transformei comentários em um único token como parte da análise lexical. O mesmo vale para seqüências de caracteres. A partir daí, a vida é fácil.

No caso específico do último analisador que criei, uma regra de escape é passada para a rotina de análise de nível superior. A regra de escape é usada para manipular tokens, como tokens de comentário, alinhados com a gramática principal. Em geral, esses tokens foram descartados.

Uma consequência de fazer dessa maneira é que, no exemplo que você postou com um comentário no meio de um identificador, o identificador não seria um único identificador - esse é o comportamento esperado em todos os idiomas (da memória) com os quais trabalhei .

O caso de um comentário dentro de uma string deve ser implicitamente tratado pela análise lexical. As regras para manipular uma sequência não têm interesse em comentários e, como tal, o comentário é tratado como o conteúdo da sequência. O mesmo se aplica a uma string (ou literal entre aspas) dentro de um comentário - a string faz parte de um comentário, que é explicitamente um único token; as regras para processar um comentário não têm interesse em cadeias.

Espero que faça sentido / ajude.


Portanto, se você tiver um código como console.log(/*a comment containing "quotes" is possible*/ "and a string containing /*slash-star, star-slash*/ is possible"), onde há aspas em um comentário e sintaxe de comentário em uma string, como o lexer saberia tokenizá-lo corretamente? Você pode editar sua resposta, fornecendo uma descrição geral desses casos?
chharvey

1

Depende de qual propósito seu analisador tem. Se você escrever um analisador para construir uma árvore de análise para compilar, um comentário não terá valor semântico além de separar os tokens potencialmente (por exemplo, método / comentário / (/ comentário /)). Neste caso, é tratado como espaços.

Se o seu analisador faz parte de um transpiler que traduz um idioma de origem para outro idioma de origem ou se o analisador é um pré-processador que pega uma unidade de compilação em um idioma de origem, analisa-o, modifica-o e grava a versão modificada novamente no mesmo idioma de origem, comenta como qualquer outra coisa se torna muito importante.

Além disso, se você possui meta informações nos comentários e se preocupa especialmente com os comentários, como ao gerar a documentação da API, como o JavaDoc, os comentários são repentinamente muito importantes.

Aqui, os comentários costumam ser anexados aos próprios tokens. Se você encontrar um comentário, anexe-o para ser um comentário de um token. Como um token pode ter vários tokens antes e depois, é novamente objetivo, dependendo de como lidar com esses comentários.

A idéia de anotar tokens sem comentários com comentários é remover completamente os comentários da gramática.

Depois de ter a árvore de análise, alguns AST começam a descompactar comentários representando cada token por seu próprio elemento AST, mas sendo anexados a outro elemento AST ao lado do relacionamento comum de contenção. Uma boa idéia é verificar todas as implementações do analisador / AST para os idiomas de origem disponíveis no IDE de código aberto.

Uma implementação muito boa é a infraestrutura do compilador Eclipse para a linguagem Java. Eles preservam os comentários durante a tokenização e representam comentários no AST - tanto quanto me lembro. Além disso, essa implementação do analisador / AST preserva a formatação.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.