2016-03-28 13 views
6

Sto utilizzando lo JSON grammar from the antlr4 grammar repository per analizzare i file JSON per un plug-in di editor. Funziona, ma riporta caratteri non validi uno per uno. I seguenti risultati frammento di errori 18 lexer:Trattare caratteri non validi come un singolo token nel lexer ANTLR4

{ 
    sometext-without-quotes : 42 
} 

voglio bollire fino a 1-2 trattando consecutivi, non validi token singolo char dello stesso tipo come una grande gettone valido.

Per una domanda simile, un lexer personalizzato è stato suggerito che colle elementi "sconosciuti" a gettoni più grandi: In antlr4 lexer, How to have a rule that catches all remaining "words" as Unknown token?

Presumo che questo bypassa la solita segnalazione degli errori lexer, che vorrei evitare, se possibile. Non c'è una soluzione adeguata per questo compito piuttosto semplice? Sembra che abbia funzionato di default in ANTLR3.

risposta

3

La risposta è nel link che hai fornito. Non voglio copiare completamente la risposta originale in modo cercherò di parafrasare un po '...

In antlr4 lexer, How to have a rule that catches all remaining "words" as Unknown token?

Aggiungere incognite al lexer che abbinerà multipli di questi ...

unknowns : Unknown+ ; 
... 
Unknown : . ; 

C'è stata una modifica a questo post per soddisfare il caso in cui si stava utilizzando solo un lexer e non si utilizza un parser. Se si utilizza un parser, non è necessario sovrascrivere il metodo nextToken perché l'errore può essere gestito nel parser in un modo molto più pulito, ad esempio unknowns sono solo un altro tipo di token per quanto riguarda il lexer. Il lexer passa questi al parser che può quindi gestire gli errori. Se si utilizza un parser riconoscerei normalmente tutti i token come token individuali e quindi nel parser emettere gli errori, ovvero raggrupparli o meno. Il motivo per cui ciò avviene è che tutta la gestione degli errori viene eseguita in un unico punto, ovvero non è nel lexer e nel parser. Inoltre rende il lexer più semplice da scrivere e testare, cioè deve riconoscere tutto il testo e non fallire mai su qualsiasi input di utf8. Alcune persone potrebbero farlo in modo diverso, ma questo ha funzionato per me con i lexer scritti a mano in C. Il parser ha il compito di determinare ciò che è effettivamente valido e come effettuare l'errore su di esso. Un altro vantaggio è che il lexer è abbastanza generico e può essere riutilizzato.

Per lexer unica soluzione ...

Controllare la risposta al link e cercare questo commento nella risposta ...

... ma ho solo un lexer, non parser ...

Gli stati risposta che l'override del metodo nextToken e va in qualche dettaglio su come farlo

@Override 
public Token nextToken() {  

e la parte importante del codice è questo ...

Token next = super.nextToken(); 

if(next.getType() != Unknown) { 
    return next; 
} 

Il codice che viene dopo questo gestisce il caso in cui è possibile abbinare i cattivi gettoni.

+0

Speravo in una soluzione semplice (il professionista blem è semplice), ma sembra che non ci sia. Grazie per la conferma. – msteiger

2

Quello che potresti fare è usare le modalità lexer. Per questo hai dovuto dividere la grammatica in parser e grammatica lessico. Iniziamo con grammatica lessicale:

JSONLexer.g4

/** Taken from "The Definitive ANTLR 4 Reference" by Terence Parr */ 

// Derived from http://json.org 
lexer grammar JSONLexer; 

STRING 
    : '"' (ESC | ~ ["\\])* '"' 
    ; 


fragment ESC 
    : '\\' (["\\/bfnrt] | UNICODE) 
    ; 


fragment UNICODE 
    : 'u' HEX HEX HEX HEX 
    ; 


fragment HEX 
    : [0-9a-fA-F] 
    ; 


NUMBER 
    : '-'? INT '.' [0-9] + EXP? | '-'? INT EXP | '-'? INT 
    ; 


fragment INT 
    : '0' | [1-9] [0-9]* 
    ; 

// no leading zeros 

fragment EXP 
    : [Ee] [+\-]? INT 
    ; 

// \- since - means "range" inside [...] 

TRUE : 'true'; 
FALSE : 'false'; 
NULL : 'null'; 

LCURL : '{'; 
RCURL : '}'; 
COL : ':'; 
COMA : ','; 
LBRACK : '['; 
RBRACK : ']'; 

WS 
    : [ \t\n\r] + -> skip 
    ; 

NON_VALID_STRING : . ->pushMode(MODE_ERR); 

mode MODE_ERR; 
WS1 
    : [ \t\n\r] + -> skip 
    ; 
COL1 : ':' ->popMode; 
MY_ERR_TOKEN : ~[':']* ->type(NON_VALID_STRING); 

Fondamentalmente ho aggiunto alcuni token utilizzati nella parte parser (come LCURL, COL, COMA ecc) e ha introdotto NON_VALID_STRING token, che è fondamentalmente il primo carattere che è niente che già è (dovrebbe essere) abbinato. Una volta rilevato questo token, si passa il lexer alla modalità MODE_ERR. In questa modalità torno alla modalità predefinita una volta rilevato : (questo può essere modificato e forse perfezionato, ma server lo scopo qui :)) o dico che tutto il resto è MY_ERR_TOKEN a cui assegno il tipo di token NON_VALID_STRING. Ecco cosa dice ATNLRWorks a questo quando ho eseguito l'opzione lexer interpretare con il proprio ingresso: ANTLRWorks lexer interpret

Così s è NON_VALID_STRING tipo e così è tutto il resto fino :. Quindi, stesso tipo ma due diversi token. Se si desidera che non siano dello stesso tipo, omettere semplicemente la chiamata type nella grammatica lessico.
Ecco la grammatica parser ora
JSONParser.g4

/** Taken from "The Definitive ANTLR 4 Reference" by Terence Parr */ 

// Derived from http://json.org 
parser grammar JSONParser; 

options { 
    tokenVocab=JSONLexer; 
} 

json 
    : object 
    | array 
    ; 

object 
    : LCURL pair (COMA pair)* RCURL 
    | LCURL RCURL 
    ; 

pair 
    : STRING COL value 
    ; 

array 
    : LBRACK value (COMA value)* RBRACK 
    | LBRACK RBRACK 
    ; 

value 
    : STRING 
    | NUMBER 
    | object 
    | array 
    | TRUE 
    | FALSE 
    | NULL 
    ; 

e se si esegue il banco di prova (lo faccio con ANTLRworks) si otterrà un singolo errore (vedi screenshot) antlworks parser


Inoltre potresti accumulare errori di lexer sovrascrivendo la classe generata di lexer, ma ho capito nella domanda che questo non è desiderato o non ho capito quella parte :)

+0

Sì, hai ragione. Grazie per la spiegazione dettagliata. Speravo in una soluzione semplice (il problema è semplice), ma sembra che non ci sia. +1 – msteiger

Problemi correlati