2012-03-08 12 views

risposta

14

Al momento, flex genera solo gli scanner a 8-bit ai limiti che in sostanza di utilizzare UTF-8. Quindi, se si dispone di un modello:

肖晗 { printf ("xiaohan\n"); } 

che funzionerà come previsto, come la sequenza di byte nel modello e nel l'ingresso sarà lo stesso. La cosa più difficile sono le classi di personaggi. Se si desidera far corrispondere né il carattere 肖 o 晗, non è possibile scrivere:

[肖晗] { printf ("xiaohan/2\n"); } 

perché questo corrisponderà ognuno dei sei byte 0xe8, 0x82, 0x96, 0xe6, 0x99 e 0x97, che significa in pratica che se fornisci 肖晗 come input, il pattern corrisponderà sei volte. Quindi, in questo semplice caso, è necessario riscrivere il pattern su (肖|晗).

Per gli intervalli, Hans Aberg ha scritto un tool in Haskell che trasforma questi in modelli a 8 bit:

Unicode> urToRegU8 0 0xFFFF 
[\0-\x7F]|[\xC2-\xDF][\x80-\xBF]|(\xE0[\xA0-\xBF]|[\xE1-\xEF][\x80-\xBF])[\x80-\xBF] 
Unicode> urToRegU32 0x00010000 0x001FFFFF 
\0[\x01-\x1F][\0-\xFF][\0-\xFF] 
Unicode> urToRegU32L 0x00010000 0x001FFFFF 
[\x01-\x1F][\0-\xFF][\0-\xFF]\0 

Questo non è abbastanza, ma dovrebbe funzionare.

+0

Ulteriori suggerimenti sulla soluzione alternativa? – xiaohan2012

+0

Ho copiato la mia risposta dalla mailing list alla risposta. –

+0

Grazie. Sembra ispirarmi molto! – xiaohan2012

15

Flex non supporta Unicode. Tuttavia, Flex supporta l'input binario "8 bit clean". Pertanto puoi scrivere schemi lessicali che corrispondono a UTF-8. È possibile utilizzare questi pattern in specifiche aree lessicali della lingua di input, ad esempio identificatori, commenti o stringhe letterali.

Questo funzionerà bene per i linguaggi di programmazione tipici, in cui è possibile essere in grado di affermare agli utenti dell'implementazione che la lingua di origine è scritta in ASCII/UTF-8 (e nessun'altra codifica è supportata, punto).

Questo approccio non funziona se lo scanner deve elaborare il testo che può essere in qualsiasi codifica. Inoltre, non funzionerà (molto bene) se è necessario esprimere regole lessicali specifiche per gli elementi Unicode. Cioè hai bisogno di caratteri Unicode e Unicode regex nello scanner stesso.

L'idea è che si può riconoscere un modello che include UTF-8 byte utilizzando una regola lex, (e poi magari prendere la yytext, e convertirlo da UTF-8 o almeno convalidarla.)

per un esempio di lavoro, vedere il codice sorgente del linguaggio TXR, in particolare questo file: http://www.kylheku.com/cgit/txr/tree/parser.l

Scorrere fino a questa sezione:

ASC  [\x00-\x7f] 
ASCN [\x00-\t\v-\x7f] 
U  [\x80-\xbf] 
U2  [\xc2-\xdf] 
U3  [\xe0-\xef] 
U4  [\xf0-\xf4] 

UANY {ASC}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} 
UANYN {ASCN}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} 
UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} 

Come si può vedere, siamo in grado di definire modelli da abbinare ASCII characte rs così come i byte di inizio e continuazione UTF-8. UTF-8 è una notazione lessicale, e questo è un generatore di analizzatori lessicali, quindi ... nessun problema!

Alcune spiegazioni: Il UANY corrisponde a qualsiasi carattere, ASCII a singolo byte o UTF-8 a più byte. UANYN significa come UANY ma non corrisponde alla nuova riga. Questo è utile per i token che non attraversano le linee, come ad esempio un commento da # alla fine della riga, contenente testo internazionale.UONLY significa corrispondere solo un carattere esteso UTF-8, non uno ASCII. Ciò è utile per scrivere una regola lex che deve escludere determinati caratteri ASCII specifici (non solo newline) ma tutti i caratteri estesi sono ok.

NOTA BENE: Si noti che le regole dello scanner utilizzano una funzione chiamata utf8_dup_from per convertire il yytext a stringhe di caratteri di larghezza contenenti codepoints Unicode. Quella funzione è robusta; rileva problemi come sequenze eccessive e byte non validi e li gestisce correttamente. Cioè questo programma non si basa su queste regole lex per eseguire la convalida e la conversione, solo per eseguire il riconoscimento lessicale di base. Queste regole riconosceranno una forma troppo lunga (come un codice ASCII codificato usando diversi byte) come sintassi valida, ma la funzione di conversione le tratterà correttamente. In ogni caso, non mi aspetto problemi di sicurezza correlati a UTF-8 nel codice sorgente del programma, dal momento che devi fidarti del codice sorgente per eseguirlo comunque (ma i dati gestiti dal programma potrebbero non essere attendibili!) Se sei scrivendo uno scanner per dati UTF-8 non attendibili, fai attenzione!

+0

Basta chiedersi, non dovrebbe la definizione di U4 essere come: 'U4 [\ xf0- \ xf7]' per realmente accogliere tutte le possibilità da 11110000 a 11110111? – exa

+0

@exa Buona attenzione ai dettagli! L'intero intervallo del byte ci darebbe punti di codice fino a 'U + 3FFFFF'. Il 'F4' limita a' U + 10FFFF'. – Kaz

+0

Mi chiedo se l'approccio proposto sia sicuro. Questi pattern TRX includono l'intervallo U + D800-U + DFFF non valido (le metriche sostitutive UTF016 sono Unicode non validi) e '{U4} {U} {U} {U}' supera il limite superiore Unicode U + 10FFFF, diversamente da quanto dichiarato dall'utente l'ultimo punto di codice dovrebbe essere '\ xf4 [\ x80- \ x8f] [\ x80- \ xbf] [\ x80- \ xbf]' non '\ xf4 [\ x80- \ xbf] [\ x80- \ xbf] [\ x80- \ XBF] '. –

1

Mi chiedo se la versione più recente di Flex supporti Unicode?

Se sì, come utilizzare i pattern per abbinare i caratteri cinesi?

per abbinare i modelli con i caratteri cinesi e di altri punti di codice Unicode con un analizzatore lessicale Flex-like, è possibile utilizzare il RE/flex lexical analyzer per C++ che è compatibile con Flex. RE/flex supporta Unicode e lavora con Bison per costruire lexer e parser.

è possibile scrivere i modelli Unicode (UTF-8 e le espressioni regolari) in specifiche flex RE/quali:

%option flex unicode 
%% 
[肖晗] { printf ("xiaohan/2\n"); } 
%% 

Usa globale %option unicode per consentire Unicode. È inoltre possibile utilizzare un modificatore locale (?u:) per limitare Unicode ad un singolo modello (quindi tutto il resto è ancora ASCII/8-bit come in Flex):

%option flex 
%% 
(?u:[肖晗]) { printf ("xiaohan/2\n"); } 
(?u:\p{Han}) { printf ("Han character %s\n", yytext); } 
.    { printf ("8-bit character %d\n", yytext[0]); } 
%% 

Opzione flex consente la compatibilità di Flex, in modo da poter usare yytext, yyleng, ECHO e così via. Senza l'opzione di flex RE/flex si aspetta LEXER chiamate di metodo: text() (o str() e wstr() per std::string e std::wstring), size() (o wsize() per un'ampia lunghezza char), e echo(). Le chiamate al metodo RE/flex sono IMHO più pulite e includono operazioni di tipo char esteso.