Come vengono generalmente analizzati i commenti?


31

Come vengono generalmente trattati i commenti nei linguaggi di programmazione e nel markup? Sto scrivendo un parser per un linguaggio di markup personalizzato e voglio seguire il principio della minima sorpresa , quindi sto cercando di determinare la convenzione generale.

Ad esempio, un commento incorporato in un token dovrebbe "interferire" con il token o no? In generale, è qualcosa di simile:

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

valido?

Inoltre, se la lingua è sensibile alle nuove righe e il commento abbraccia la nuova riga, la nuova riga dovrebbe essere considerata o no?

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

essere trattato come

stuff stuff more stuff

o

stuff stuff
more stuff

?

So cosa fanno alcune lingue specifiche, né cerco opinioni, ma cerco o meno: c'è un consenso generale su cosa ci si aspetta generalmente da un mark up per quanto riguarda token e nuove righe?


Il mio contesto particolare è un markup simile a un wiki.


La newline esiste all'interno del commento? Perché dovrebbe essere trattato in modo diverso rispetto a qualsiasi altro personaggio nel commento?

1
@Snowman c'è quella prospettiva, ma d'altra parte se il token 'x' ha un significato speciale se è il primo token sulla linea e sembra essere il primo token sulla linea sia per la persona che guarda l'origine che per lettura parser riga per riga. Sembra un dilemma, quindi ho posto la domanda.
Slitta

4
Avevo bisogno di farlo esattamente alle specifiche qualche tempo fa e ho trovato che i documenti di gcc sono una risorsa eccellente. Ci sono alcuni strani casi angolari che potresti non aver considerato.
Karl Bielefeldt,

Risposte:


40

Di solito i commenti vengono scansionati (e scartati) come parte del processo di tokenizzazione, ma prima dell'analisi. Un commento funziona come un separatore di token anche in assenza di spazi bianchi attorno ad esso.

Come sottolineato, la specifica C afferma esplicitamente che i commenti sono sostituiti da un singolo spazio. Tuttavia, è solo un gergo di specifiche, dal momento che un parser del mondo reale in realtà non sostituirà nulla, ma scansionerà e scarterà un commento nello stesso modo in cui scansiona e scarta i caratteri degli spazi bianchi. Spiega in modo semplice che un commento separa i token nello stesso modo in cui lo farebbe uno spazio.

Il contenuto dei commenti viene ignorato, quindi le interruzioni di riga all'interno dei commenti su più righe non hanno alcun effetto. I linguaggi sensibili alle interruzioni di riga (Python e Visual Basic) di solito non hanno commenti multilinea, ma JavaScript è un'eccezione. Per esempio:

return /*
       */ 17

È equivalente a

return 17

non

return
17

I commenti a riga singola mantengono l'interruzione di riga, ovvero

return // single line comment
    17

è equivalente a

return
17

non

return 17

Poiché i commenti vengono scansionati ma non analizzati, tendono a non annidarsi. Così

 /*  /* nested comment */ */

è un errore di sintassi, poiché il commento viene aperto dal primo /*e chiuso dal primo*/


3
Nella maggior parte delle lingue i commenti in linea ( /* like this */) sono considerati uguali a un singolo spazio bianco e i commenti con terminazione EOL ( // like this) a una riga vuota.
9000,

@JacquesB quindi sto pensando di considerare i commenti come sostituiti nella loro interezza dalla fonte come uno spazio a larghezza zero , che sembra essere equivalente a quello che stai suggerendo.
Slitta

1
@artb uno spazio ordinario dovrebbe funzionare bene e si trova nella tabella codici ASCII.
John Dvorak,

@JanDvorak uno spazio influirà sull'aspetto e rimuoverà la comprensione ed è più vicino alla semantica di "un commento non è davvero lì". L'output di rendering primario sarà HTML, quindi nel mio caso ASCII non è un problema in quanto i browser supportano Unicode. Detto questo, credo che i mandati standard C prevedano che i commenti vengano sostituiti con un unico spazio.
Slitta

1
Alcune lingue, in particolare Racket, hanno annidato commenti multilinea: (define x #| this is #| a sub-comment |# the main comment |# 3) xrese 3.
wchargin,

9

Per rispondere alla domanda:

c'è un consenso generale su cosa ci si aspetta generalmente da un mark up?

Direi che nessuno si aspetterebbe che un commento incorporato in un token sia legale.

Come regola generale, i commenti devono essere trattati come gli spazi bianchi. Qualsiasi posto che sarebbe valido per avere spazi bianchi estranei dovrebbe anche avere un commento incorporato. L'unica eccezione sarebbero le stringhe:

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

Sarebbe abbastanza strano sostenere i commenti all'interno delle stringhe e renderebbe noiosa la loro fuga!


2
Non ho mai pensato alle stringhe, questo è un buon caso limite. Il mio pensiero attuale era fare una semplice regex tra l'inizio e la fine del commento e sostituendolo con un singolo spazio. Ciò avrebbe scatenato il tuo caso.
Slitta

3
+1 per quel bit sull'evasione delle stringhe. Anche se, nel tuo esempio, mi aspetto generalmente che stampi Hello /* world*/!piuttosto che sopprimere i delimitatori di commento. Inoltre, benvenuti ai programmatori!
settembre

1
Grazie 8bittree! Ed è totalmente quello che volevo dire. Stranamente, ho anche bisogno di sfuggire al ** nella mia risposta ....
Connor Clark,

2
@ArtB in generale, "l'analisi per sostituzione" diventa molto complicato lungo la strada con casi limite e interazione con altre funzionalità, ed è meglio evitare dall'inizio.
Hobbs,

7

Nei linguaggi insensibili agli spazi bianchi, i caratteri ignorati (ovvero gli spazi bianchi o quelli che fanno parte di un commento) delimitano i token.

Quindi, ad esempio, ci Sys temsono due token, mentre Systemè uno. L'utilità di questo potrebbe essere più evidente se si confronta new Foo()e newFoo()uno dei quali costruirà un'istanza di Foomentre l'altro chiama newFoo.

I commenti possono svolgere lo stesso ruolo di una serie di spazi bianchi, ad esempio new/**/Foo()funziona come new Foo(). Naturalmente questo può essere più complesso, ad esempio new /**/ /**/ Foo()o quant'altro.

Tecnicamente, dovrebbe essere possibile consentire commenti all'interno degli identificatori, ma dubito che sia particolarmente pratico.

Ora, che dire dei linguaggi sensibili agli spazi bianchi?

Python mi viene in mente e ha una risposta molto semplice: nessun commento in blocco. Inizi un commento #e poi il parser funziona esattamente come se il resto della riga non esistesse ma fosse solo una nuova riga.

Al contrario, giada consente commenti di blocco , in cui il blocco termina quando torni allo stesso livello di rientro. Esempio:

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

Quindi, in questo regno, non direi che si potrebbe dire come le cose vengono di solito gestite. Quello che sembra essere un punto in comune, è che un commento termina sempre con un fine riga, il che significa che tutti i commenti si comportano esattamente come le nuove righe.


Hmm, la nuova riga è il vero problema poiché stiamo usando la sintassi HTML \ XML per i commenti, quindi sarà multilinea.
Slitta

3
@ArtB Se stai usando la sintassi HTML / XML, potrebbe essere saggio usare semplicemente il loro comportamento.
8bittree,

1
@ 8bittree ha senso, avrebbe dovuto pensarci. Lascerò la domanda così com'è poiché sarà più utile in questo modo.
Slitta

3

In passato ho trasformato i commenti in un singolo token come parte dell'analisi lessicale. Lo stesso vale per le stringhe. Da lì, la vita è facile.

Nel caso specifico dell'ultimo parser che ho creato, una regola di escape viene passata alla routine di analisi di livello superiore. La regola di escape viene utilizzata per gestire token come token di commento in linea con la grammatica di base. In generale, questi token sono stati scartati.

Una conseguenza di ciò è che nell'esempio che hai pubblicato con un commento nel mezzo di un identificatore, l'identificatore non sarebbe un singolo identificatore - questo è il comportamento previsto in tutte le lingue (dalla memoria) con cui ho lavorato .

Il caso di un commento all'interno di una stringa dovrebbe essere implicitamente gestito dall'analisi lessicale. Le regole per gestire una stringa non hanno interesse per i commenti e come tali il commento viene considerato come il contenuto della stringa. Lo stesso vale per una stringa (o letterale tra virgolette) all'interno di un commento: la stringa fa parte di un commento, che è esplicitamente un singolo token; le regole per l'elaborazione di un commento non hanno interesse per le stringhe.

Spero che abbia senso / aiuti.


Quindi se hai un codice come console.log(/*a comment containing "quotes" is possible*/ "and a string containing /*slash-star, star-slash*/ is possible"), dove ci sono virgolette in un commento e una sintassi di commento in una stringa, come farebbe il lexer a riconoscerlo correttamente? Potete per favore modificare la vostra risposta, fornendo una descrizione generale di questi casi?
Chharvey,

1

Dipende dallo scopo del tuo parser. Se si scrive un parser per creare un albero di analisi per la compilazione di un commento non ha alcun valore semantico accanto ai token potenzialmente separatori (ad esempio metodo / commento / (/ commento /)). In questo caso, è trattato come spazi.

Se il tuo parser fa parte di un transpiler che traduce una lingua di origine in un'altra lingua di origine o se il tuo parser è un preprocessore che prende un'unità di compilazione in una lingua di origine, analizzandola, modificandola e riscrivendo la versione modificata nella stessa lingua di origine, commenti come qualsiasi altra cosa diventa molto importante.

Inoltre, se hai commenti meta nei commenti e ti preoccupi particolarmente dei commenti come quando si genera documentazione API come fa JavaDoc, i commenti sono all'improvviso molto importanti.

Qui i commenti sono spesso allegati ai token stessi. Se trovi un commento, lo allevi come commento di un token. Poiché un token può avere più token prima e dopo, dipende di nuovo da come gestire tali commenti.

L'idea di annotare token non-comment con avere commenti è di rimuovere del tutto i commenti dalla grammatica.

Una volta che hai l'albero di analisi, alcuni AST iniziano a decomprimere i commenti che rappresentano ogni token dal proprio elemento AST ma che sono collegati a un altro elemento AST accanto alla solita relazione contiene. Una buona idea è quella di controllare tutte le implementazioni parser / AST per le lingue di origine disponibili nell'IDE open source.

Un'implementazione molto buona è l'infrastruttura del compilatore Eclipse per il linguaggio Java. Conservano i commenti durante la tokenizzazione e rappresentano i commenti all'interno dell'AST - per quanto mi ricordo. Inoltre, questa implementazione parser / AST mantiene la formattazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.