blob: 02dbad3085cfd9b0a3bc130e3e27766e082969ce [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 2002-2004, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.dev.tool.localeconverter;
import java.io.*;
/**
* An escape transition parses a POSIX escape sequence. An escape
* sequence can be a hex, octal, or decimal constant, or an escaped
* character. The resultant value is ALWAYS on byte long. Longer
* escaped values (ie.\xFF63) overflow and are truncated. An escape
* character followed by an EOL sequence is silently eaten.
*/
public class EscapeTransition extends ComplexTransition {
public static final EscapeTransition GLOBAL = new EscapeTransition(SUCCESS);
public static final char DEFAULT_ESCAPE_CHAR = '\\';
public static char ESCAPE_CHAR = DEFAULT_ESCAPE_CHAR;
private static final int DECIMAL = 1; //decimal escape sequence was parsed
private static final int OCTAL = 2; //octal escape sequence was parsed
private static final int HEX = 3; //hex escape sequence was parsed
private static final int ESCAPE = 4; //character escape sequence was parsed
private static final int EOL = 5; //an escape character followed by EOF eaten
private static final String OCTAL_CHARS = "01234567";
private static final String DECIMAL_CHARS = "0123456789";
private static final String HEX_CHARS = "0123456789abcdefABCDEF";
/** Set the escape character to the default */
public static synchronized char setDefaultEscapeChar() {
return setEscapeChar(DEFAULT_ESCAPE_CHAR);
}
/** Set the escape character */
public static synchronized char setEscapeChar(char c) {
char result = ESCAPE_CHAR;
ESCAPE_CHAR = c;
theStates = null;
return result;
}
public EscapeTransition(int success) {
super(success);
//{{INIT_CONTROLS
//}}
}
public boolean accepts(int c) {
return ESCAPE_CHAR == (char)c;
}
/** Convert the accepted text into the appropriate unicode character */
protected void handleSuccess(Lex parser, StringBuffer output) throws IOException {
switch (parser.getState()) {
case DECIMAL:
output.append((char)parser.dataAsNumber(10));
break;
case OCTAL:
output.append((char)parser.dataAsNumber(8));
break;
case HEX:
output.append((char)parser.dataAsNumber(16));
break;
case ESCAPE:
parser.appendDataTo(output);
break;
case EOL:
//silently eat the EOL characters
break;
default:
//should never get here
throw new Lex.ParseException("Internal error parsing escape sequence");
// parser.appendDataTo(output);
}
}
/** return the states for this transaction */
protected Lex.Transition[][] getStates() {
synchronized (getClass()) {
if (theStates == null) {
//cache the states so they can be shared. They must
//be rebuilt when the escape character is changed.
theStates = new Lex.Transition[][] {
{ //state 0:
new Lex.CharTransition(ESCAPE_CHAR, Lex.IGNORE_CONSUME, -1),
new Lex.ParseExceptionTransition("illegal escape character")
},
{ //state 1:
new Lex.EOFTransition(OCTAL),
new Lex.CharTransition('d', Lex.IGNORE_CONSUME, -3),
new Lex.CharTransition('x', Lex.IGNORE_CONSUME, -2),
new Lex.StringTransition(OCTAL_CHARS, Lex.ACCUMULATE_CONSUME, -4),
new Lex.CharTransition(ESCAPE_CHAR, Lex.ACCUMULATE_CONSUME, ESCAPE),
new EOLTransition(EOL),
new Lex.DefaultTransition(Lex.ACCUMULATE_CONSUME, ESCAPE)
},
{ //state 2: hex
new Lex.EOFTransition(HEX),
new Lex.StringTransition(HEX_CHARS, Lex.ACCUMULATE_CONSUME, -2),
new Lex.DefaultTransition(Lex.IGNORE_PUTBACK, HEX)
},
{ //state 3: decimal
new Lex.EOFTransition(DECIMAL),
new Lex.StringTransition(DECIMAL_CHARS, Lex.ACCUMULATE_CONSUME, -3),
new Lex.DefaultTransition(Lex.IGNORE_PUTBACK, DECIMAL)
},
{ //state 4: octal
new Lex.EOFTransition(OCTAL),
new Lex.StringTransition(OCTAL_CHARS, Lex.ACCUMULATE_CONSUME, -4),
new Lex.DefaultTransition(Lex.IGNORE_PUTBACK, OCTAL)
},
};
}
}
return theStates;
}
private static Lex.Transition[][] theStates = null;
public static void main(String[] args) {
try {
Lex.Transition[][] states = {{
new EscapeTransition(SUCCESS),
new Lex.EOFTransition(),
new Lex.ParseExceptionTransition("bad test input")
}};
String text = "\\d100\\xAf\\\\\\777\\\n\\123\\x2028\\x2029";
StringReader sr = new StringReader(text);
PushbackReader pr = new PushbackReader(sr);
Lex parser = new Lex(states, pr);
//parser.debug(true);
int s = parser.nextToken();
while (s == SUCCESS) {
System.out.println(parser.getState());
s = parser.nextToken();
}
} catch (Exception e) {
System.out.println(e);
}
}
//{{DECLARE_CONTROLS
//}}
}