Derivazione dell'espressione regolare per C-style / ** / commenti


8

Sto lavorando a un parser per un linguaggio in stile C, e per quel parser ho bisogno dell'espressione regolare che corrisponde a C-style / ** / commenti. Ora, ho trovato questa espressione sul web:

/\*([^\*]*\*+[^\*/])*([^\*]*\*+|[^\*]*\*/

Tuttavia, come puoi vedere, questa è un'espressione piuttosto confusa e non ho idea se corrisponda esattamente a ciò che voglio che corrisponda.

Esiste un modo diverso di definire (rigorosamente) le espressioni regolari che sono facili da verificare a mano che sono veramente corrette e quindi convertibili ('compilabili') nell'espressione regolare sopra?


2
Si noti che questo approccio impedisce commenti nidificati. Se stai comunque costruendo un parser completo, potresti considerare di analizzare i commenti dei blocchi "correttamente". non solo è destinato a essere più chiaro, ma puoi anche leggere metadati strutturati dai commenti, se lo desideri.
Raffaello

I frammenti erano (!\*)destinati? Intendi la notazione più comune [^*]? E cosa (!*|!/)?
Gilles 'SO-smetti di essere malvagio' il

@Gilles: ho aggiornato l'espressione. (! * |! /) vuole essere qualcosa che non è né * né /.
Alex ten Brink,

@Raphael, nei commenti C non annidano .
vonbrand,

@vonbrand: "C-style" non è molto specifico, quindi menzionare che un "miglioramento naturale" non è possibile è un punto valido.
frafl

Risposte:


6

Posso pensare a quattro modi:

  1. Definisci un automa per la lingua che ti interessa. Converti l'espressione regolare in un automa (usando i derivati ​​di Brzozowski). Verificare che entrambi gli automi accettino la stessa lingua (determinare e minimizzare o utilizzare un argomento di bisimulazione).

  2. Scrivi un sacco di casi di test e applica la tua espressione regolare a loro.

  3. Converti l'automa definito al punto 1 in un'espressione regolare, usando tecniche standard.

  4. Una combinazione di quanto sopra.


5

Se vuoi essere sicuro di analizzare i commenti in C, devi confrontare il tuo modello con la specifica C. C99 §6.4.9 definisce la sintassi dei commenti come segue:

1. Tranne che all'interno di una costante di carattere, una stringa letterale o un commento, i caratteri /* introducono un commento. Il contenuto di tale commento viene esaminato solo per identificare i caratteri multibyte e per trovare i caratteri */che lo terminano.

2. Tranne all'interno di una costante di carattere, una stringa letterale o un commento, i personaggi //introducono un commento che include tutti i caratteri multibyte fino al successivo carattere di nuova riga, ma non incluso. Il contenuto di tale commento viene esaminato solo per identificare i caratteri multibyte e per trovare il carattere di nuova riga che termina.

Questa è la prosa inglese, non una definizione formale, ma esiste un'interpretazione ragionevolmente chiara in termini di un automa finito non deterministico (NFA) che consuma un commento:

  • Dallo stato iniziale, /seguito da *entra nello stato di commento su più righe e /seguito da /entra nello stato di commento su riga singola.
  • Dallo stato del commento su più righe, *seguito da /entra nello stato post-commento.
  • Dallo stato di commento a riga singola, una nuova riga entra nello stato di post commento.
  • Qualsiasi altro personaggio lascia invariato lo stato.

Nota che per sapere se si applica lo stato iniziale, devi eseguire un po 'più di analisi per rilevare letterali di stringhe e caratteri.

Una volta che hai un NFA, puoi usare le tecniche standard per costruire un'espressione regolare (non le vedo negli articoli di Wikipedia, ma dovrebbero essere discusse nei libri di testo).

Se hai già un'espressione regolare e desideri testarla, puoi confrontare la sua lingua generata con quella della NFA dedotta dalla specifica della lingua: l'uguaglianza delle lingue regolari è decidibile. Un modo per decidere l'uguaglianza è costruire un automa deterministico minimo per ciascuno; se le lingue sono equivalenti, i DFA minimi saranno isomorfi.


Una ricerca su Google Libri fornisce questo riferimento all'algoritmo di Kleene: books.google.co.uk/…
rgrig

0

Se stai scrivendo un parser, questo tipo di cose è gestita dall'analizzatore lessicale. E lì puoi esprimerlo con espressioni regolari o (come flexmostrano gli esempi che ho visto) semplicemente "scappare nel linguaggio sottostante" e finire il lavoro lì. Cioè, nel vedere /*basta saltare avanti fino a trovare */(un DFA per questo è facile da costruire, e da lì un frammento C è semplice da scrivere).

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.