Code example for StreamTokenizer

Methods: nextToken, toString

0
     * An unchecked exception that is thrown when encountering a syntax 
     * or semantic error in the input. 
     */ 
    public static class ParseException extends IllegalArgumentException {
        ParseException(StreamTokenizer state, String expected) {
            super("expected " + expected + ", saw " + state.toString());
        } 
    } 
 
    // A sentinel instance used to indicate a null string. 
    static final String NULL_STRING = new String("<TypedProperties:NULL_STRING>");
 
    // Constants used to represent the supported types. 
    static final int TYPE_UNSET = 'x';
    static final int TYPE_BOOLEAN = 'Z';
    static final int TYPE_BYTE = 'I' | 1 << 8;
    // TYPE_CHAR: character literal syntax not supported; use short. 
    static final int TYPE_SHORT = 'I' | 2 << 8;
    static final int TYPE_INT = 'I' | 4 << 8;
    static final int TYPE_LONG = 'I' | 8 << 8;
    static final int TYPE_FLOAT = 'F' | 4 << 8;
    static final int TYPE_DOUBLE = 'F' | 8 << 8;
    static final int TYPE_STRING = 'L' | 's' << 8;
    static final int TYPE_ERROR = -1;
 
    /** 
     * Converts a string to an internal type constant. 
     * 
     * @param typeName the type name to convert 
     * @return the type constant that corresponds to {@code typeName}, 
     *         or {@code TYPE_ERROR} if the type is unknown 
     */ 
    static int interpretType(String typeName) {
        if ("unset".equals(typeName)) {
            return TYPE_UNSET;
        } else if ("boolean".equals(typeName)) {
            return TYPE_BOOLEAN;
        } else if ("byte".equals(typeName)) {
            return TYPE_BYTE;
        } else if ("short".equals(typeName)) {
            return TYPE_SHORT;
        } else if ("int".equals(typeName)) {
            return TYPE_INT;
        } else if ("long".equals(typeName)) {
            return TYPE_LONG;
        } else if ("float".equals(typeName)) {
            return TYPE_FLOAT;
        } else if ("double".equals(typeName)) {
            return TYPE_DOUBLE;
        } else if ("String".equals(typeName)) {
            return TYPE_STRING;
        } 
        return TYPE_ERROR;
    } 
 
    /** 
     * Parses the data in the reader. 
     * 
     * @param r The {@code Reader} containing input data to parse 
     * @param map The {@code Map} to insert parameter values into 
     * @throws ParseException if the input data is malformed 
     * @throws IOException if there is a problem reading from the {@code Reader} 
     */ 
    static void parse(Reader r, Map<String, Object> map) throws ParseException, IOException {
        final StreamTokenizer st = initTokenizer(r);
 
        /* A property name must be a valid fully-qualified class + package name. 
         * We don't support Unicode, though. 
         */ 
        final String identifierPattern = "[a-zA-Z_$][0-9a-zA-Z_$]*";
        final Pattern propertyNamePattern =
            Pattern.compile("(" + identifierPattern + "\\.)*" + identifierPattern);
 
 
        while (true) { 
            int token;
 
            // Read the next token, which is either the type or EOF. 
            token = st.nextToken();
            if (token == StreamTokenizer.TT_EOF) {
                break; 
            } 
            if (token != StreamTokenizer.TT_WORD) {
                throw new ParseException(st, "type name");
            } 
            final int type = interpretType(st.sval);
            if (type == TYPE_ERROR) {
                throw new ParseException(st, "valid type name");
            } 
            st.sval = null;
 
            if (type == TYPE_UNSET) {
                // Expect '('. 
                token = st.nextToken();
                if (token != '(') {
                    throw new ParseException(st, "'('");
                } 
            } 
 
            // Read the property name. 
            token = st.nextToken();
            if (token != StreamTokenizer.TT_WORD) {
                throw new ParseException(st, "property name");
            } 
            final String propertyName = st.sval;
            if (!propertyNamePattern.matcher(propertyName).matches()) {
                throw new ParseException(st, "valid property name");
            } 
            st.sval = null;
 
            if (type == TYPE_UNSET) {
                // Expect ')'. 
                token = st.nextToken();
                if (token != ')') {
                    throw new ParseException(st, "')'");
                } 
                map.remove(propertyName);
            } else { 
                // Expect '='. 
                token = st.nextToken();
                if (token != '=') {
                    throw new ParseException(st, "'='");
                } 
 
                // Read a value of the appropriate type, and insert into the map. 
                final Object value = parseValue(st, type);
                final Object oldValue = map.remove(propertyName);
                if (oldValue != null) {
                    // TODO: catch the case where a string is set to null and then 
                    //       the same property is defined with a different type. 
                    if (value.getClass() != oldValue.getClass()) {
                        throw new ParseException(st,
                            "(property previously declared as a different type)"); 
                    } 
                } 
                map.put(propertyName, value);
            } 
 
            // Expect ';'. 
            token = st.nextToken();
            if (token != ';') {
                throw new ParseException(st, "';'");
            } 
        } 
    } 
 
    /** 
     * Parses the next token in the StreamTokenizer as the specified type. 
     * 
     * @param st The token source 
     * @param type The type to interpret next token as 
     * @return a Boolean, Number subclass, or String representing the value. 
     *         Null strings are represented by the String instance NULL_STRING 
     * @throws IOException if there is a problem reading from the {@code StreamTokenizer} 
     */ 
    static Object parseValue(StreamTokenizer st, final int type) throws IOException {
        final int token = st.nextToken();
 
        if (type == TYPE_BOOLEAN) {
            if (token != StreamTokenizer.TT_WORD) {
                throw new ParseException(st, "boolean constant");
            }