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: 
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) 
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 :)
Speravo in una soluzione semplice (il professionista blem è semplice), ma sembra che non ci sia. Grazie per la conferma. – msteiger