È appropriato che un tokenizzatore usi la regex per raccogliere token?

2

Recentemente ho rilevato il bug "Toy Language" e ho sperimentato varie configurazioni semplici di tokenizer. La più recente utilizza la libreria boost.regex per identificare e ottenere il valore dei token. Mi sembra che regex sia il modo migliore per andare, quando si crea un tokenizer. La mia ricerca ha dimostrato che la mia ipotesi è falsa, o almeno non completamente vera.

Questo è ciò che un utente di Stack Overflow ha dovuto dire riguardo a una domanda su: È una cattiva idea usare regex tokenken string per lexer? :

Using regular expressions is THE traditional way to generate your tokens.

Dopo aver fatto ulteriori ricerche su questo argomento, mi sono reso conto che anche i generatori di lexer più popolari usano regex. Ad esempio, prendi il generatore di lexer Lex :

Lex helps write programs whose control flow is directed by instances of regular expressions in the input stream. It is well suited for editor-script type transformations and for segmenting input in preparation for a parsing routine. - http://dinosaur.compilertools.net/lex/.

Questo mi porta a trarre la conclusione che regex è il solito modo preferito per creare un tokenizer. Dopo aver cercato ancora una volta il mio argomento e tentato di trovare un secondo parere, ho trovato questa affermazione in risposta a questa domanda su Stack Overflow:

The reason why people tell you that regular expressions aren't the best idea for a case like this is because regular expressions take more time to evaluate, and the regular expression language has many limitations and quirks that make it unsuitable for many applications. - user:670358

E ha continuato a dire

Many compilers use a basic single-pass tokenization algorithm. The tokenizer has a very basic idea of what can be used as a delimiter, how constants and identifiers should be treated, etc. The tokenizer will then just iterate through the input quickly and emit a string of tokens that can then be easily parsed. - user:670358

Questo mi ha lasciato confuso e contemplando diverse cose:

  • È regex necessario per un tokenizzatore creato a mano. O è eccessivo?
  • Se la regex non viene usata spesso, allora quanto sono estrapolati i token?

Questo può o non può essere basato su opinioni, ma credo che ci sia un metodo / metodo preferito tra i programmatori.

    
posta Christian Dean 02.09.2016 - 09:19
fonte

2 risposte

3

I regex funzionano alla grande per lexing / tokenization.

TL; DR

Usare le espressioni regolari per tokenize è del tutto appropriato. L'approccio predefinito, davvero. Per quanto riguarda l'efficienza, le regex si riferiscono tradizionalmente direttamente alle macchine a stati finiti . Sono tanto semplici ed efficienti quanto è possibile ottenere per definizioni di sintassi di qualsiasi generalità.

ImodernimotoriregexnonsonopureimplementazionimatematichediFSM,essendostatiestesiconfunzionalitàcomelook-ahead,look-behindebacktracking.Mahannounstrongfondamentoteorico,einpraticasonoaltamenteottimizzatiedestremamentebencontrollati.

Granpartedegliultimicinquantaepiùannidianalisidellinguaggioinformaticosiriduconoatrovaretecnicheperdistricareilprocessoerenderlopratico.Dividereeconquistare/stratificareècomune.Quindil'ideadidividereilproblemadicomprensionedellinguaggioinunlivelloinferiore"lexing" e "analizzare" il livello superiore.

Lo stesso con la ricerca di approcci che riducono la forza come l'utilizzo di solo sottoinsiemi di senza contesto e grammatiche prive di ambiguità . Pascal era limitato a ciò che poteva essere analizzato ricorsivo-discendente , e Python è notoriamente limitato a LL(1) . Ci sono zuppe alfabetiche complete di LL, LR, SLR, LALR, ecc. Grammatiche linguistiche / famiglie di parser. Quasi tutti i progetti linguistici implementati sono attentamente limitati dalle tecniche di analisi che usano. Perl è l'unica lingua principale che posso pensare che non sia così limitata. Questa danza è descritta nel "Libro dei draghi" che erano i più comuni "come lingua" libri di testo per generazioni .

Il rigoroso scomporre lexing / parsing e 'usare solo sottoinsiemi di regole grammaticali prive di ambiguità, che si attenuano. A volte la comprensione lessicale non è suddivisa in uno strato completamente diverso e la maggior parte dei sistemi ha abbastanza potenza e memoria della CPU per renderla fattibile. Un'altra risposta menzionata PEG parser. Ciò inizia a rompere l'ortodossia delle famiglie linguistiche. Ancora più lontano puoi vedere un rinnovato interesse per parser / grammatiche più generali come il parser Earley che va oltre le limitate previsioni delle aristocrazie LL / LR. Recenti implementazioni e perfezionamenti (ad esempio Marpa ) mostrano che , su hardware moderno, non c'è davvero alcuna barriera all'analisi generalizzata.

Tutto ciò che ha detto, tuttavia, la libertà infinita (o anche molta più grande libertà) non è necessariamente una buona cosa. Le restrizioni meccaniche, pratiche e tecniche di qualsiasi forma d'arte - scrittura, pittura, scultura, produzione cinematografica, codifica, ecc. - richiedono spesso una disciplina di approccio che è utile al di là delle corrispondenti tecniche di implementazione disponibili. Python, ad esempio, potrebbe essere notevolmente migliorato generalizzando oltre l'analisi di LL (1)? Non è chiaro che lo sarebbe. Certo, ci sono alcune incoerenze e limitazioni sfortunate, e ha bisogno di uno spazio vuoto significativo. Ma rimane anche pulito e coerente, attraverso un vasto numero di sviluppatori e usi, parzialmente come conseguenza di tali restrizioni. Non fare l'equivalente in lingua di ciò che è accaduto quando diversi tipi di facce, dimensioni, colori, colori di sfondo, variazioni e decorazioni sono diventati ampiamente disponibili nei word processor e nelle e-mail. Non utilizzare tutte le opzioni in modo profuso e indiscriminato. Non è un buon design.

Quindi, mentre grandi generalità e persino ambiguità sono ora aperte a te mentre implementa il tuo linguaggio giocattolo, e mentre puoi sicuramente usare uno dei nuovi approcci PEG o Earley, a meno che tu non stia scrivendo qualcosa che imita il linguaggio naturale umano, probabilmente non è necessario. Sarebbe sufficiente l'approccio standard di lessering e parsing. Oppure, per farla breve, le regex vanno bene.

    
risposta data 02.09.2016 - 18:53
fonte
4

L'uso di espressioni regolari per tokenize è un approccio classico. Gli approcci più moderni all'analisi dovrebbero utilizzare un parser basato su PEG ( "parser di espressioni di analisi" ).

In entrambi i casi funziona, ma avere la capacità di lasciare "ciò che è stato analizzato finora" guida ciò che costituisce un token dà una certa flessibilità. In sostanza, un parser in stile PEG intreccia la tokenizzazione e l'analisi, mentre un approccio rigoroso "tokenize parse stream of token" offre meno flessibilità nella progettazione della lingua, ma di solito non è un problema.

Per quanto riguarda le "espressioni regolari che richiedono più tempo per valutare", si tratta più di un problema di qualità di implementazione rispetto a un problema fondamentale con le espressioni regolari. Tuttavia, essi sono limitati in ciò che possono esprimere, ma per il compito di tokenizzazione questi limiti non sono tipicamente un problema (i RE hanno problemi nell'esprimere concetti come "parentesi arbitrariamente annidate", che è ben oltre la tokenizzazione).

    
risposta data 02.09.2016 - 10:54
fonte

Leggi altre domande sui tag