You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ml...@apache.org on 2006/04/19 09:50:13 UTC

svn commit: r395158 [2/3] - in /incubator/harmony/enhanced/classlib/trunk/modules/regex/src: main/java/java/util/regex/ test/java/org/apache/harmony/tests/java/util/regex/

Modified: incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/Lexer.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/Lexer.java?rev=395158&r1=395157&r2=395158&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/Lexer.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/Lexer.java Wed Apr 19 00:50:10 2006
@@ -1,918 +1,955 @@
-/*
- *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-/**
- * @author Nikolay A. Kuznetsov
- * @version $Revision: 1.21.2.2 $
- */
-package java.util.regex;
-
-import java.util.MissingResourceException;
-
-/**
- * The purpose of this class is to break given pattern into RE tokens; 
- * 
- * @author Nikolay A. Kuznetsov
- * @version $Revision: 1.21.2.2 $
- */
-class Lexer {
-
-    public static final int CHAR_DOLLAR = 0xe0000000 | '$';
-
-    public static final int CHAR_RIGHT_PARENTHESIS = 0xe0000000 | ')';
-
-    public static final int CHAR_LEFT_SQUARE_BRACKET = 0xe0000000 | '[';
-
-    public static final int CHAR_RIGHT_SQUARE_BRACKET = 0xe0000000 | ']';
-
-    public static final int CHAR_CARET = 0xe0000000 | '^';
-
-    public static final int CHAR_VERTICAL_BAR = 0xe0000000 | '|';
-
-    public static final int CHAR_AMPERSAND = 0xe0000000 | '&';
-
-    public static final int CHAR_HYPHEN = 0xe0000000 | '-';
-
-    public static final int CHAR_DOT = 0xe0000000 | '.';
-
-    public static final int QMOD_GREEDY = 0xe0000000;
-
-    public static final int QMOD_RELUCTANT = 0xc0000000;
-
-    public static final int QMOD_POSSESSIVE = 0x80000000;
-
-    public static final int QUANT_STAR = QMOD_GREEDY | '*';
-
-    public static final int QUANT_STAR_P = QMOD_POSSESSIVE | '*';
-
-    public static final int QUANT_STAR_R = QMOD_RELUCTANT | '*';
-
-    public static final int QUANT_PLUS = QMOD_GREEDY | '+';
-
-    public static final int QUANT_PLUS_P = QMOD_POSSESSIVE | '+';
-
-    public static final int QUANT_PLUS_R = QMOD_RELUCTANT | '+';
-
-    public static final int QUANT_ALT = QMOD_GREEDY | '?';
-
-    public static final int QUANT_ALT_P = QMOD_POSSESSIVE | '?';
-
-    public static final int QUANT_ALT_R = QMOD_RELUCTANT | '?';
-
-    public static final int QUANT_COMP = QMOD_GREEDY | '{';
-
-    public static final int QUANT_COMP_P = QMOD_POSSESSIVE | '{';
-
-    public static final int QUANT_COMP_R = QMOD_RELUCTANT | '{';
-
-    public static final int CHAR_LEFT_PARENTHESIS = 0x80000000 | '(';
-
-    public static final int CHAR_NONCAP_GROUP = 0xc0000000 | '(';
-
-    public static final int CHAR_POS_LOOKAHEAD = 0xe0000000 | '(';
-
-    public static final int CHAR_NEG_LOOKAHEAD = 0xf0000000 | '(';
-
-    public static final int CHAR_POS_LOOKBEHIND = 0xf8000000 | '(';
-
-    public static final int CHAR_NEG_LOOKBEHIND = 0xfc000000 | '(';
-
-    public static final int CHAR_ATOMIC_GROUP = 0xfe000000 | '(';
-
-    public static final int CHAR_FLAGS = 0xff000000 | '(';
-
-    public static final int CHAR_START_OF_INPUT = 0x80000000 | 'A';
-
-    public static final int CHAR_WORD_BOUND = 0x80000000 | 'b';
-
-    public static final int CHAR_NONWORD_BOUND = 0x80000000 | 'B';
-
-    public static final int CHAR_PREVIOUS_MATCH = 0x80000000 | 'G';
-
-    public static final int CHAR_END_OF_INPUT = 0x80000000 | 'z';
-
-    public static final int CHAR_END_OF_LINE = 0x80000000 | 'Z';
-
-    public static final int MODE_PATTERN = 1 << 0;
-
-    public static final int MODE_RANGE = 1 << 1;
-
-    public static final int MODE_ESCAPE = 1 << 2;
-
-    private char[] pattern = null;
-
-    private int flags = 0;
-
-    private int mode = 1;
-
-    // when in literal mode, this field will save the previous one
-    private int saved_mode = 0;
-
-    private int length = 0;
-
-    // previous char read
-    private int lookBack;
-
-    //current character read
-    private int ch;
-
-    //next character
-    private int lookAhead;
-
-    // cur special token
-    private SpecialToken curST = null;
-    
-    // next special token
-    private SpecialToken lookAheadST = null;
-
-    //  cur char being processed
-    private int index = 0; 
-
-    //  previous non-whitespace character index;
-    private int prevNW = 0; 
-
-    //  cur token start index
-    private int curToc = 0; 
-
-    //  look ahead token index
-    private int lookAheadToc = 0; 
-
-    //  original string representing pattern    
-    private String orig = null; 
-
-    public Lexer(String pattern, int flags) {
-        orig = pattern;
-        if ((flags & Pattern.LITERAL) > 0) {
-            pattern = Pattern.quote(pattern);
-        } else if ((flags & Pattern.CANON_EQ) > 0) {
-            pattern = normalize(pattern);
-        }
-
-        this.pattern = new char[pattern.length() + 2];
-        System.arraycopy(pattern.toCharArray(), 0, this.pattern, 0, pattern
-                .length());
-        this.pattern[this.pattern.length - 1] = this.pattern[this.pattern.length - 2] = 0;
-
-        this.flags = flags;
-        // read first two tokens;
-        movePointer();
-        movePointer();
-
-    }
-
-    /**
-     * Returns current character w/o reading next one; if there are no more
-     * characters returns 0;
-     * 
-     * @return current character;
-     */
-    public int peek() {
-        return ch;
-    }
-
-    /**
-     * Set the Lexer to PATTERN or RANGE mode; Lexer interpret character two
-     * different ways in parser or range modes.
-     * 
-     * @param mode
-     *            Lexer.PATTERN or Lexer.RANGE
-     */
-    public void setMode(int mode) {
-        if (mode > 0 && mode < 3) {
-            this.mode = mode;
-        }
-
-        if (mode == Lexer.MODE_PATTERN) {
-            reread();
-        }
-    }
-
-    public void setFlags(int flags) {
-        if (((this.flags ^ flags) & Pattern.COMMENTS) != 0) {
-            this.flags = flags;
-            reread();
-        }
-
-        this.flags = flags;
-    }
-
-    public SpecialToken peekSpecial() {
-        return curST;
-    }
-
-    /**
-     * Returns true, if current token is special, i.e. quantifier, or other 
-     * compound token.
-     * 
-     * @return - true if current token is special, false otherwise.
-     */
-    public boolean isSpecial() {
-        return curST != null;
-    }
-
-    public boolean isQuantifier() {
-        return isSpecial() && curST.getType() == SpecialToken.TOK_QUANTIFIER;
-    }
-
-    public boolean isNextSpecial() {
-        return lookAheadST != null;
-    }
-
-    /**
-     * Returns current character and moves string index to the next one;
-     * 
-     */
-    public int next() {
-        movePointer();
-        return lookBack;
-    }
-
-    /**
-     * Returns current special token and moves string index to the next one;
-     */
-    public SpecialToken nextSpecial() {
-        SpecialToken res = curST;
-        movePointer();
-        return res;
-    }
-
-    /**
-     * Returns nest symbol read.
-     */
-    public int lookAhead() {
-        return lookAhead;
-    }
-
-    /**
-     * Returns previous character.
-     */
-    public int back() {
-        return lookBack;
-    }
-
-    /**
-     * Normalize given expression
-     */
-    private String normalize(String pattern) {
-        // TODO this code is workaround in the abcence of unicode normalization
-        return pattern;
-    }
-
-    /**
-     * Reread current character, may be require if previous token changes mode
-     * to one with different character interpretation.
-     *
-     */
-    private void reread() {
-        lookAhead = ch;
-        lookAheadST = curST;
-        index = lookAheadToc;
-        lookAheadToc = curToc;
-        movePointer();
-    }
-
-    /**
-     * Moves pointer one position right; save current character to lookBack;
-     * lookAhead to current one and finaly read one more to lookAhead;
-     */
-    private void movePointer() {
-        // swap pointers
-        lookBack = ch;
-        ch = lookAhead;
-        curST = lookAheadST;
-        curToc = lookAheadToc;
-        lookAheadToc = index;
-        boolean reread;
-        do {
-            reread = false;
-            // read next character analize it and construct token:
-            // //
-            lookAhead = (index < pattern.length) ? pattern[nextIndex()] : 0;
-            lookAheadST = null;
-
-            if (mode == Lexer.MODE_ESCAPE) {
-                if (lookAhead == '\\') {
-                    lookAhead = (index < pattern.length) ? pattern[nextIndex()]
-                            : 0;
-
-                    switch (lookAhead) {
-                    case 'E': {
-                        mode = saved_mode;
-                        lookAhead = (index < pattern.length - 2) ? pattern[nextIndex()]
-                                : 0;
-                        break;
-                    }
-
-                    default: {
-                        lookAhead = '\\';
-                        index = prevNW;
-                        return;
-                    }
-                    }
-                } else {
-                    return;
-                }
-            }
-
-            if (lookAhead == '\\') {
-                lookAhead = (index < pattern.length - 2) ? pattern[nextIndex()]
-                        : -1;
-                switch (lookAhead) {
-                case -1:
-                    throw new PatternSyntaxException(I18n
-                            .getMessage("Trailing \\"), this.toString(), index);
-                case 'P':
-                case 'p': {
-                    String cs = parseCharClassName();
-                    boolean negative = false;
-
-                    if (lookAhead == 'P')
-                        negative = true;
-                    ;
-                    try {
-                        lookAheadST = AbstractCharClass.getPredefinedClass(cs,
-                                negative);
-                    } catch (MissingResourceException mre) {
-                        throw new PatternSyntaxException(I18n
-                                .getFormattedMessage(
-                                        "Character Class \\p'{'{0}'}'"
-                                                + "is not supported", cs), this
-                                .toString(), index);
-                    }
-                    lookAhead = 0;
-                    break;
-                }
-
-                case 'w':
-                case 's':
-                case 'd':
-                case 'W':
-                case 'S':
-                case 'D': {
-                    lookAheadST = CharClass.getPredefinedClass(new String(
-                            pattern, prevNW, 1), false);
-                    lookAhead = 0;
-                    break;
-                }
-
-                case 'Q': {
-                    saved_mode = mode;
-                    mode = Lexer.MODE_ESCAPE;
-                    reread = true;
-                    break;
-                }
-
-                case 't':
-                    lookAhead = '\t';
-                    break;
-                case 'n':
-                    lookAhead = '\n';
-                    break;
-                case 'r':
-                    lookAhead = '\r';
-                    break;
-                case 'f':
-                    lookAhead = '\f';
-                    break;
-                case 'a':
-                    lookAhead = '\u0007';
-                    break;
-                case 'e':
-                    lookAhead = '\u001B';
-                    break;
-
-                case '1':
-                case '2':
-                case '3':
-                case '4':
-                case '5':
-                case '6':
-                case '7':
-                case '8':
-                case '9': {
-                    if (mode == Lexer.MODE_PATTERN) {
-                        lookAhead = 0x80000000 | lookAhead;
-                    }
-                    break;
-                }
-
-                case '0':
-                    lookAhead = readOctals();
-                    break;
-                case 'x':
-                    lookAhead = readHex("hexadecimal", 2);
-                    break;
-                case 'u':
-                    lookAhead = readHex("Unicode", 4);
-                    break;
-
-                case 'b':
-                    lookAhead = CHAR_WORD_BOUND;
-                    break;
-                case 'B':
-                    lookAhead = CHAR_NONWORD_BOUND;
-                    break;
-                case 'A':
-                    lookAhead = CHAR_START_OF_INPUT;
-                    break;
-                case 'G':
-                    lookAhead = CHAR_PREVIOUS_MATCH;
-                    break;
-                case 'Z':
-                    lookAhead = CHAR_END_OF_LINE;
-                    break;
-                case 'z':
-                    lookAhead = CHAR_END_OF_INPUT;
-                    break;
-                case 'c': {
-                    if (index < pattern.length - 2) {
-                        lookAhead = (pattern[nextIndex()] & 0x1f);
-                        break;
-                    } else {
-                        throw new PatternSyntaxException("Illegal unsupported "
-                                + "control sequence", this.toString(), index);
-                    }
-                }
-                case 'C':
-                case 'E':
-                case 'F':
-                case 'H':
-                case 'I':
-                case 'J':
-                case 'K':
-                case 'L':
-                case 'M':
-                case 'N':
-                case 'O':
-                case 'R':
-                case 'T':
-                case 'U':
-                case 'V':
-                case 'X':
-                case 'Y':
-                case 'g':
-                case 'h':
-                case 'i':
-                case 'j':
-                case 'k':
-                case 'l':
-                case 'm':
-                case 'o':
-                case 'q':
-                case 'y':
-                    throw new PatternSyntaxException("Illegal unsupported "
-                            + "escape sequence", this.toString(), index);
-
-                default:
-                    break;
-                }
-            } else if (mode == Lexer.MODE_PATTERN) {
-                switch (lookAhead) {
-                case '+':
-                case '*':
-                case '?': {
-                    char mod = (index < pattern.length) ? pattern[index] : '*';
-                    switch (mod) {
-                    case '+': {
-                        lookAhead = lookAhead | Lexer.QMOD_POSSESSIVE;
-                        nextIndex();
-                        break;
-                    }
-                    case '?': {
-                        lookAhead = lookAhead | Lexer.QMOD_RELUCTANT;
-                        nextIndex();
-                        break;
-                    }
-                    default: {
-                        lookAhead = lookAhead | Lexer.QMOD_GREEDY;
-                        break;
-                    }
-                    }
-
-                    break;
-                }
-
-                case '{': {
-                    lookAheadST = processQuantifier(lookAhead);
-                    break;
-                }
-
-                case '$':
-                    lookAhead = CHAR_DOLLAR;
-                    break;
-                case '(': {
-                    if (pattern[index] == '?') {
-                        nextIndex();
-                        char nonCap = pattern[index];
-                        boolean behind = false;
-                        do {
-                            if (!behind) {
-                                switch (nonCap) {
-                                case '!':
-                                    lookAhead = CHAR_NEG_LOOKAHEAD;
-                                    nextIndex();
-                                    break;
-                                case '=':
-                                    lookAhead = CHAR_POS_LOOKAHEAD;
-                                    nextIndex();
-                                    break;
-                                case '>':
-                                    lookAhead = CHAR_ATOMIC_GROUP;
-                                    nextIndex();
-                                    break;
-                                case '<': {
-                                    nextIndex();
-                                    nonCap = pattern[index];
-                                    behind = true;
-                                    break;
-                                }
-                                default: {
-                                    lookAhead = readFlags();
-                                    if (lookAhead >= 128) {
-                                        lookAhead = (lookAhead & 0x7f) << 16;
-                                        flags = lookAhead;
-                                        lookAhead = CHAR_FLAGS | lookAhead;
-                                    } else {
-                                        lookAhead = lookAhead << 16;
-                                        lookAhead = CHAR_NONCAP_GROUP
-                                                | lookAhead;
-                                    }
-                                    break;
-                                }
-                                }
-                            } else {
-                                behind = false;
-                                switch (nonCap) {
-                                case '!':
-                                    lookAhead = CHAR_NEG_LOOKBEHIND;
-                                    nextIndex();
-                                    break;
-                                case '=':
-                                    lookAhead = CHAR_POS_LOOKBEHIND;
-                                    nextIndex();
-                                    break;
-                                default:
-                                    throw new PatternSyntaxException("Unknown "
-                                            + "look behind", this.toString(),
-                                            index);
-                                }
-                            }
-                        } while (behind);
-                    } else {
-                        lookAhead = CHAR_LEFT_PARENTHESIS;
-                    }
-                    break;
-                }
-
-                case ')':
-                    lookAhead = CHAR_RIGHT_PARENTHESIS;
-                    break;
-                case '[': {
-                    lookAhead = CHAR_LEFT_SQUARE_BRACKET;
-                    setMode(Lexer.MODE_RANGE);
-                    break;
-                }
-                case ']': {
-                    if (mode == Lexer.MODE_RANGE) {
-                        lookAhead = CHAR_RIGHT_SQUARE_BRACKET;
-                    }
-                    break;
-                }
-                case '^':
-                    lookAhead = CHAR_CARET;
-                    break;
-                case '|':
-                    lookAhead = CHAR_VERTICAL_BAR;
-                    break;
-                case '.':
-                    lookAhead = CHAR_DOT;
-                    break;
-                default:
-                    break;
-                }
-            } else if (mode == Lexer.MODE_RANGE) {
-                switch (lookAhead) {
-                case '[':
-                    lookAhead = CHAR_LEFT_SQUARE_BRACKET;
-                    break;
-                case ']':
-                    lookAhead = CHAR_RIGHT_SQUARE_BRACKET;
-                    break;
-                case '^':
-                    lookAhead = CHAR_CARET;
-                    break;
-                case '&':
-                    lookAhead = CHAR_AMPERSAND;
-                    break;
-                case '-':
-                    lookAhead = CHAR_HYPHEN;
-                    break;
-                default:
-                    break;
-                }
-            }
-        } while (reread);
-    }
-
-    /**
-     * Parse character classes names and verifies correction of the syntax;
-     */
-    private String parseCharClassName() {
-        StringBuffer sb = new StringBuffer(10);
-        if (index < pattern.length - 2) {
-            // one symbol family
-            if (pattern[index] != '{') {
-                return "Is" + new String(pattern, nextIndex(), 1);
-            }
-
-            nextIndex();
-            char ch = 0;
-            while (index < pattern.length - 2
-                    && (ch = pattern[nextIndex()]) != '}') {
-                sb.append((char) ch);
-            }
-            if (ch != '}')
-                throw new PatternSyntaxException(I18n
-                        .getMessage("Unclosed character family"), this
-                        .toString(), index);
-        }
-
-        if (sb.length() == 0)
-            throw new PatternSyntaxException(I18n
-                    .getMessage("Empty character family"), this.toString(),
-                    index);
-
-        String res = sb.toString();
-        if (res.length() == 1)
-            return "Is" + res;
-        return (res.length() > 3 && (res.startsWith("Is") || res
-                .startsWith("In"))) ? res.substring(2) : res;
-    }
-
-    /**
-     * Process given character in assumption that it's quantifier.
-     */
-    private Quantifier processQuantifier(int ch) {
-        StringBuffer sb = new StringBuffer(4);
-        int min = -1;
-        int max = Integer.MAX_VALUE;
-        while (index < pattern.length && (ch = pattern[nextIndex()]) != '}') {
-            if (ch == ',' && min < 0) {
-                try {
-                    min = Integer.parseInt(sb.toString(), 10);
-                    sb.delete(0, sb.length());
-                } catch (NumberFormatException nfe) {
-                    throw new PatternSyntaxException(I18n
-                            .getMessage("Incorrect Quantifier Syntax"), this
-                            .toString(), index);
-                }
-            } else {
-                sb.append((char) ch);
-            }
-        }
-        if (ch != '}') {
-            throw new PatternSyntaxException(I18n
-                    .getMessage("Incorrect Quantifier Syntax"),
-                    this.toString(), index);
-        }
-        if (sb.length() > 0) {
-            try {
-                max = Integer.parseInt(sb.toString(), 10);
-                if (min < 0)
-                    min = max;
-            } catch (NumberFormatException nfe) {
-                throw new PatternSyntaxException(I18n
-                        .getMessage("Incorrect Quantifier Syntax"), this
-                        .toString(), index);
-            }
-        } else if (min < 0) {
-            throw new PatternSyntaxException(I18n
-                    .getMessage("Incorrect Quantifier Syntax"),
-                    this.toString(), index);
-        }
-        if ((min | max | max - min) < 0) {
-            throw new PatternSyntaxException(I18n
-                    .getMessage("Incorrect Quantifier Syntax"),
-                    this.toString(), index);
-        }
-
-        char mod = (index < pattern.length) ? pattern[index] : '*';
-
-        switch (mod) {
-        case '+':
-            lookAhead = Lexer.QUANT_COMP_P;
-            nextIndex();
-            break;
-        case '?':
-            lookAhead = Lexer.QUANT_COMP_R;
-            nextIndex();
-            break;
-        default:
-            lookAhead = Lexer.QUANT_COMP;
-            break;
-        }
-        return new Quantifier(min, max);
-    }
-
-    public String toString() {
-        return orig;
-    }
-
-    /**
-     * Checks if there are any characters in the pattern.
-     * 
-     * @return true if there are no more characters in the pattern.
-     */
-    public boolean isEmpty() {
-        return ch == 0 && lookAhead == 0 && !isSpecial();
-    }
-
-    /**
-     * Returns true if current character is plain token.
-     */
-    public static boolean isLetter(int ch) {
-        return ch >= 0;
-    }
-
-    /**
-     * Return true if current character is letter, false otherwise; This is
-     * shortcut to static method isLetter to check the current character.
-     * 
-     * @return true if current character is letter, false otherwise
-     */
-    public boolean isLetter() {
-        return !isEmpty() && !isSpecial() && isLetter(ch);
-    }
-
-    /**
-     * Process hexadecimal integer. 
-     */
-    private int readHex(String radixName, int max) {
-        StringBuffer st = new StringBuffer(max);
-        int length = pattern.length - 2;
-        int i;
-        for (i = 0; i < max && index < length; i++) {
-            st.append((char) pattern[nextIndex()]);
-        }
-        if (i == max) {
-            try {
-                return Integer.parseInt(st.toString(), 16);
-            } catch (NumberFormatException nfe) {
-            }
-        }
-
-        throw new PatternSyntaxException(I18n.getMessage("Invalid " + radixName
-                + "escape sequence"), this.toString(), index);
-    }
-
-    /**
-     * Process octal integer.
-     */
-    private int readOctals() {
-        char ch;
-        int max = 3;
-        int i = 1;
-        int first;
-        int res;
-        int length = pattern.length - 2;
-
-        switch (first = Character.digit((ch = pattern[index]), 8)) {
-        case -1:
-            throw new PatternSyntaxException(I18n.getMessage("Invalid "
-                    + "octal escape sequence"), this.toString(), index);
-        default: {
-            if (first > 3)
-                max--;
-            nextIndex();
-            res = first;
-        }
-        }
-
-        while (i < max && index < length
-                && (first = Character.digit((ch = pattern[index]), 8)) >= 0) {
-            res = res * 8 + first;
-            nextIndex();
-            i++;
-        }
-
-        return res;
-    }
-
-    /**
-     * Process expression flags givent with (?idmsux-idmsux)
-     */
-    private int readFlags() {
-        char ch;
-        boolean pos = true;
-        int res = flags;
-        int neg = 0;
-        while (index < pattern.length) {
-            ch = pattern[index];
-            switch (ch) {
-            case '-': {
-                if (!pos)
-                    throw new PatternSyntaxException("Illegal "
-                            + "inline construct", this.toString(), index);
-                pos = false;
-            }
-
-            case 'i':
-                res = pos ? res | Pattern.CASE_INSENSITIVE : res
-                        ^ Pattern.CASE_INSENSITIVE & res;
-                break;
-            case 'd':
-                res = pos ? res | Pattern.UNIX_LINES : res ^ Pattern.UNIX_LINES
-                        & res;
-                break;
-            case 'm':
-                res = pos ? res | Pattern.MULTILINE : res ^ Pattern.MULTILINE
-                        & res;
-                break;
-            case 's':
-                res = pos ? res | Pattern.DOTALL : res ^ Pattern.DOTALL & res;
-                break;
-            case 'u':
-                res = pos ? res | Pattern.UNICODE_CASE : res
-                        ^ Pattern.UNICODE_CASE & res;
-                break;
-            case 'x':
-                res = pos ? res | Pattern.COMMENTS : res ^ Pattern.COMMENTS
-                        & res;
-                break;
-            case ':':
-                nextIndex();
-                return res;
-            case ')':
-                nextIndex();
-                return res | (1 << 7);
-            default:
-                throw new PatternSyntaxException("Illegal inline construct",
-                        this.toString(), index);
-            }
-            nextIndex();
-        }
-        throw new PatternSyntaxException("Illegal inline construct", this
-                .toString(), index);
-    }
-
-    /**
-     * Returns next character index to read and moves pointer to the next one.
-     * If comments flag is on this method will skip comments and whitespaces.
-     * 
-     * The following actions are equivalent if comments flag is off ch =
-     * pattern[index++] == ch = pattern[nextIndex]
-     * 
-     * @return next character index to read.
-     */
-    private int nextIndex() {
-        prevNW = index;
-        if ((flags & Pattern.COMMENTS) != 0) {
-            skipComments();
-        } else {
-            index++;
-        }
-        return prevNW;
-    }
-
-    /**
-     * Skips comments and whitespaces
-     */
-    private int skipComments() {
-        int length = pattern.length - 2;
-        index++;
-        do {
-            while (index < length && Character.isWhitespace(pattern[index]))
-                index++;
-            if (index < length && pattern[index] == '#') {
-                index++;
-                while (index < length && !isLineSeparator(pattern[index]))
-                    index++;
-            } else
-                return index;
-        } while (true);
-    }
-
-    private boolean isLineSeparator(int ch) {
-        return (ch == '\n' || ch == '\r' || ch == '\u0085' || (ch | 1) == '\u2029');
-    }
-
-    /**
-     * Returns the curr. character index.
-     */
-    public int getIndex() {
-        return curToc;
-    }
-}
+/*
+ *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Nikolay A. Kuznetsov
+ * @version $Revision: 1.21.2.2 $
+ */
+package java.util.regex;
+
+import java.util.MissingResourceException;
+
+/**
+ * The purpose of this class is to break given pattern into RE tokens; 
+ * 
+ * @author Nikolay A. Kuznetsov
+ * @version $Revision: 1.21.2.2 $
+ */
+class Lexer {
+
+    public static final int CHAR_DOLLAR = 0xe0000000 | '$';
+
+    public static final int CHAR_RIGHT_PARENTHESIS = 0xe0000000 | ')';
+
+    public static final int CHAR_LEFT_SQUARE_BRACKET = 0xe0000000 | '[';
+
+    public static final int CHAR_RIGHT_SQUARE_BRACKET = 0xe0000000 | ']';
+
+    public static final int CHAR_CARET = 0xe0000000 | '^';
+
+    public static final int CHAR_VERTICAL_BAR = 0xe0000000 | '|';
+
+    public static final int CHAR_AMPERSAND = 0xe0000000 | '&';
+
+    public static final int CHAR_HYPHEN = 0xe0000000 | '-';
+
+    public static final int CHAR_DOT = 0xe0000000 | '.';
+
+    public static final int QMOD_GREEDY = 0xe0000000;
+
+    public static final int QMOD_RELUCTANT = 0xc0000000;
+
+    public static final int QMOD_POSSESSIVE = 0x80000000;
+
+    public static final int QUANT_STAR = QMOD_GREEDY | '*';
+
+    public static final int QUANT_STAR_P = QMOD_POSSESSIVE | '*';
+
+    public static final int QUANT_STAR_R = QMOD_RELUCTANT | '*';
+
+    public static final int QUANT_PLUS = QMOD_GREEDY | '+';
+
+    public static final int QUANT_PLUS_P = QMOD_POSSESSIVE | '+';
+
+    public static final int QUANT_PLUS_R = QMOD_RELUCTANT | '+';
+
+    public static final int QUANT_ALT = QMOD_GREEDY | '?';
+
+    public static final int QUANT_ALT_P = QMOD_POSSESSIVE | '?';
+
+    public static final int QUANT_ALT_R = QMOD_RELUCTANT | '?';
+
+    public static final int QUANT_COMP = QMOD_GREEDY | '{';
+
+    public static final int QUANT_COMP_P = QMOD_POSSESSIVE | '{';
+
+    public static final int QUANT_COMP_R = QMOD_RELUCTANT | '{';
+
+    public static final int CHAR_LEFT_PARENTHESIS = 0x80000000 | '(';
+
+    public static final int CHAR_NONCAP_GROUP = 0xc0000000 | '(';
+
+    public static final int CHAR_POS_LOOKAHEAD = 0xe0000000 | '(';
+
+    public static final int CHAR_NEG_LOOKAHEAD = 0xf0000000 | '(';
+
+    public static final int CHAR_POS_LOOKBEHIND = 0xf8000000 | '(';
+
+    public static final int CHAR_NEG_LOOKBEHIND = 0xfc000000 | '(';
+
+    public static final int CHAR_ATOMIC_GROUP = 0xfe000000 | '(';
+
+    public static final int CHAR_FLAGS = 0xff000000 | '(';
+
+    public static final int CHAR_START_OF_INPUT = 0x80000000 | 'A';
+
+    public static final int CHAR_WORD_BOUND = 0x80000000 | 'b';
+
+    public static final int CHAR_NONWORD_BOUND = 0x80000000 | 'B';
+
+    public static final int CHAR_PREVIOUS_MATCH = 0x80000000 | 'G';
+
+    public static final int CHAR_END_OF_INPUT = 0x80000000 | 'z';
+
+    public static final int CHAR_END_OF_LINE = 0x80000000 | 'Z';
+
+    public static final int MODE_PATTERN = 1 << 0;
+
+    public static final int MODE_RANGE = 1 << 1;
+
+    public static final int MODE_ESCAPE = 1 << 2;
+
+    private char[] pattern = null;
+
+    private int flags = 0;
+
+    private int mode = 1;
+
+    // when in literal mode, this field will save the previous one
+    private int saved_mode = 0;
+
+    // previous char read
+    private int lookBack;
+
+    //current character read
+    private int ch;
+
+    //next character
+    private int lookAhead;
+    
+    //index of last char in pattern plus one
+    private int patternFullLength = 0;
+
+    // cur special token
+    private SpecialToken curST = null;
+    
+    // next special token
+    private SpecialToken lookAheadST = null;
+
+    //  cur char being processed
+    private int index = 0; 
+
+    //  previous non-whitespace character index;
+    private int prevNW = 0; 
+
+    //  cur token start index
+    private int curToc = 0; 
+
+    //  look ahead token index
+    private int lookAheadToc = 0; 
+
+    //  original string representing pattern    
+    private String orig = null; 
+
+    public Lexer(String pattern, int flags) {
+        orig = pattern;
+        if ((flags & Pattern.LITERAL) > 0) {
+            pattern = Pattern.quote(pattern);
+        } else if ((flags & Pattern.CANON_EQ) > 0) {
+            pattern = normalize(pattern);
+        }
+
+        this.pattern = new char[pattern.length() + 2];
+        System.arraycopy(pattern.toCharArray(), 0, this.pattern, 0, 
+ 		       pattern.length());
+        this.pattern[this.pattern.length - 1] = 0;
+        this.pattern[this.pattern.length - 2] = 0;        
+        patternFullLength = this.pattern.length;
+        this.flags = flags;
+        // read first two tokens;
+        movePointer();
+        movePointer();
+
+    }
+
+    /**
+     * Returns current character w/o reading next one; if there are no more
+     * characters returns 0;
+     * 
+     * @return current character;
+     */
+    public int peek() {
+        return ch;
+    }
+
+    /**
+     * Set the Lexer to PATTERN or RANGE mode; Lexer interpret character two
+     * different ways in parser or range modes.
+     * 
+     * @param mode
+     *            Lexer.PATTERN or Lexer.RANGE
+     */
+    public void setMode(int mode) {
+        if (mode > 0 && mode < 3) {
+            this.mode = mode;
+        }
+
+        if (mode == Lexer.MODE_PATTERN) {
+            reread();
+        }
+    }
+
+    /**
+     * Restores flags for Lexer
+     * 
+     * @param flags
+     */
+    public void restoreFlags(int flags) {
+        this.flags = flags;
+    	lookAhead = ch;
+    	lookAheadST = curST;
+    	        
+    	//curToc is an index of closing bracket )
+    	index = curToc + 1;
+        lookAheadToc = curToc;        
+    	movePointer();
+    }
+
+    public SpecialToken peekSpecial() {
+        return curST;
+    }
+
+    /**
+     * Returns true, if current token is special, i.e. quantifier, or other 
+     * compound token.
+     * 
+     * @return - true if current token is special, false otherwise.
+     */
+    public boolean isSpecial() {
+        return curST != null;
+    }
+
+    public boolean isQuantifier() {
+        return isSpecial() && curST.getType() == SpecialToken.TOK_QUANTIFIER;
+    }
+
+    public boolean isNextSpecial() {
+        return lookAheadST != null;
+    }
+
+    /**
+     * Returns current character and moves string index to the next one;
+     * 
+     */
+    public int next() {
+        movePointer();
+        return lookBack;
+    }
+
+    /**
+     * Returns current special token and moves string index to the next one;
+     */
+    public SpecialToken nextSpecial() {
+        SpecialToken res = curST;
+        movePointer();
+        return res;
+    }
+
+    /**
+     * Returns nest symbol read.
+     */
+    public int lookAhead() {
+        return lookAhead;
+    }
+
+    /**
+     * Returns previous character.
+     */
+    public int back() {
+        return lookBack;
+    }
+
+    /**
+     * Normalize given expression
+     */
+    private String normalize(String pattern) {
+        // TODO this code is workaround in the abcence of unicode normalization
+        return pattern;
+    }
+
+    /**
+     * Reread current character, may be require if previous token changes mode
+     * to one with different character interpretation.
+     *
+     */
+    private void reread() {
+        lookAhead = ch;
+        lookAheadST = curST;
+        index = lookAheadToc;
+        lookAheadToc = curToc;
+        movePointer();
+    }
+
+    /**
+     * Moves pointer one position right; save current character to lookBack;
+     * lookAhead to current one and finaly read one more to lookAhead;
+     */
+    private void movePointer() {
+        // swap pointers
+        lookBack = ch;
+        ch = lookAhead;
+        curST = lookAheadST;
+        curToc = lookAheadToc;
+        lookAheadToc = index;
+        boolean reread;
+        do {
+            reread = false;
+            // read next character analize it and construct token:
+            // //
+            lookAhead = (index < pattern.length) ? pattern[nextIndex()] : 0;
+            lookAheadST = null;
+
+            if (mode == Lexer.MODE_ESCAPE) {
+                if (lookAhead == '\\') {
+                    lookAhead = (index < pattern.length) ? pattern[nextIndex()]
+                            : 0;
+
+                    switch (lookAhead) {
+                    case 'E': {
+                    	mode = saved_mode;
+                        lookAhead = (index <= pattern.length - 2) 
+                                    ? pattern[nextIndex()] 
+                                    : 0;
+                        break;
+                    }
+
+                    default: {
+                        lookAhead = '\\';
+                        index = prevNW;
+                        return;
+                    }
+                    }
+                } else {
+                    return;
+                }
+            }
+
+            if (lookAhead == '\\') {
+                lookAhead = (index < pattern.length - 2) ? pattern[nextIndex()]
+                        : -1;
+                switch (lookAhead) {
+                case -1:
+                    throw new PatternSyntaxException(I18n
+                            .getMessage("Trailing \\"), this.toString(), index);
+                case 'P':
+                case 'p': {
+                    String cs = parseCharClassName();
+                    boolean negative = false;
+
+                    if (lookAhead == 'P')
+                        negative = true;
+                    ;
+                    try {
+                        lookAheadST = AbstractCharClass.getPredefinedClass(cs,
+                                negative);
+                    } catch (MissingResourceException mre) {
+                        throw new PatternSyntaxException(I18n
+                                .getFormattedMessage(
+                                        "Character Class \\p'{'{0}'}'"
+                                                + "is not supported", cs), this
+                                .toString(), index);
+                    }
+                    lookAhead = 0;
+                    break;
+                }
+
+                case 'w':
+                case 's':
+                case 'd':
+                case 'W':
+                case 'S':
+                case 'D': {
+                    lookAheadST = CharClass.getPredefinedClass(new String(
+                            pattern, prevNW, 1), false);
+                    lookAhead = 0;
+                    break;
+                }
+
+                case 'Q': {
+                    saved_mode = mode;
+                    mode = Lexer.MODE_ESCAPE;
+                    reread = true;
+                    break;
+                }
+
+                case 't':
+                    lookAhead = '\t';
+                    break;
+                case 'n':
+                    lookAhead = '\n';
+                    break;
+                case 'r':
+                    lookAhead = '\r';
+                    break;
+                case 'f':
+                    lookAhead = '\f';
+                    break;
+                case 'a':
+                    lookAhead = '\u0007';
+                    break;
+                case 'e':
+                    lookAhead = '\u001B';
+                    break;
+
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9': {
+                    if (mode == Lexer.MODE_PATTERN) {
+                        lookAhead = 0x80000000 | lookAhead;
+                    }
+                    break;
+                }
+
+                case '0':
+                    lookAhead = readOctals();
+                    break;
+                case 'x':
+                    lookAhead = readHex("hexadecimal", 2);
+                    break;
+                case 'u':
+                    lookAhead = readHex("Unicode", 4);
+                    break;
+
+                case 'b':
+                    lookAhead = CHAR_WORD_BOUND;
+                    break;
+                case 'B':
+                    lookAhead = CHAR_NONWORD_BOUND;
+                    break;
+                case 'A':
+                    lookAhead = CHAR_START_OF_INPUT;
+                    break;
+                case 'G':
+                    lookAhead = CHAR_PREVIOUS_MATCH;
+                    break;
+                case 'Z':
+                    lookAhead = CHAR_END_OF_LINE;
+                    break;
+                case 'z':
+                    lookAhead = CHAR_END_OF_INPUT;
+                    break;
+                case 'c': {
+                    if (index < pattern.length - 2) {
+                        lookAhead = (pattern[nextIndex()] & 0x1f);
+                        break;
+                    } else {
+                        throw new PatternSyntaxException("Illegal unsupported "
+                                + "control sequence", this.toString(), index);
+                    }
+                }
+                case 'C':
+                case 'E':
+                case 'F':
+                case 'H':
+                case 'I':
+                case 'J':
+                case 'K':
+                case 'L':
+                case 'M':
+                case 'N':
+                case 'O':
+                case 'R':
+                case 'T':
+                case 'U':
+                case 'V':
+                case 'X':
+                case 'Y':
+                case 'g':
+                case 'h':
+                case 'i':
+                case 'j':
+                case 'k':
+                case 'l':
+                case 'm':
+                case 'o':
+                case 'q':
+                case 'y':
+                    throw new PatternSyntaxException("Illegal unsupported "
+                            + "escape sequence", this.toString(), index);
+
+                default:
+                    break;
+                }
+            } else if (mode == Lexer.MODE_PATTERN) {
+                switch (lookAhead) {
+                case '+':
+                case '*':
+                case '?': {
+                    char mod = (index < pattern.length) ? pattern[index] : '*';
+                    switch (mod) {
+                    case '+': {
+                        lookAhead = lookAhead | Lexer.QMOD_POSSESSIVE;
+                        nextIndex();
+                        break;
+                    }
+                    case '?': {
+                        lookAhead = lookAhead | Lexer.QMOD_RELUCTANT;
+                        nextIndex();
+                        break;
+                    }
+                    default: {
+                        lookAhead = lookAhead | Lexer.QMOD_GREEDY;
+                        break;
+                    }
+                    }
+
+                    break;
+                }
+
+                case '{': {
+                    lookAheadST = processQuantifier(lookAhead);
+                    break;
+                }
+
+                case '$':
+                    lookAhead = CHAR_DOLLAR;
+                    break;
+                case '(': {
+                    if (pattern[index] == '?') {
+                        nextIndex();
+                        char nonCap = pattern[index];
+                        boolean behind = false;
+                        do {
+                            if (!behind) {
+                                switch (nonCap) {
+                                case '!':
+                                    lookAhead = CHAR_NEG_LOOKAHEAD;
+                                    nextIndex();
+                                    break;
+                                case '=':
+                                    lookAhead = CHAR_POS_LOOKAHEAD;
+                                    nextIndex();
+                                    break;
+                                case '>':
+                                    lookAhead = CHAR_ATOMIC_GROUP;
+                                    nextIndex();
+                                    break;
+                                case '<': {
+                                    nextIndex();
+                                    nonCap = pattern[index];
+                                    behind = true;
+                                    break;
+                                }
+                                default: {
+                                    lookAhead = readFlags();
+                                    
+                                    /*
+                                     * We return res = res | 1 << 8
+                                     * from readFlags() if we read
+                                     * (?idmsux-idmsux)
+                                     */
+                                    if (lookAhead >= 256) {
+                                    	
+                                    	//Erase auxiliaury bit
+                                    	lookAhead = (lookAhead & 0xff);    
+                                    	flags = lookAhead;
+                                    	lookAhead = lookAhead << 16;
+                                        lookAhead = CHAR_FLAGS | lookAhead;
+                                    } else {
+                                    	flags = lookAhead;
+                                        lookAhead = lookAhead << 16;
+                                        lookAhead = CHAR_NONCAP_GROUP
+                                                    | lookAhead;
+                                    }
+                                    break;                                
+                                }
+                                }
+                            } else {
+                                behind = false;
+                                switch (nonCap) {
+                                case '!':
+                                    lookAhead = CHAR_NEG_LOOKBEHIND;
+                                    nextIndex();
+                                    break;
+                                case '=':
+                                    lookAhead = CHAR_POS_LOOKBEHIND;
+                                    nextIndex();
+                                    break;
+                                default:
+                                    throw new PatternSyntaxException("Unknown "
+                                            + "look behind", this.toString(),
+                                            index);
+                                }
+                            }
+                        } while (behind);
+                    } else {
+                        lookAhead = CHAR_LEFT_PARENTHESIS;
+                    }
+                    break;
+                }
+
+                case ')':
+                    lookAhead = CHAR_RIGHT_PARENTHESIS;
+                    break;
+                case '[': {
+                    lookAhead = CHAR_LEFT_SQUARE_BRACKET;
+                    setMode(Lexer.MODE_RANGE);
+                    break;
+                }
+                case ']': {
+                    if (mode == Lexer.MODE_RANGE) {
+                        lookAhead = CHAR_RIGHT_SQUARE_BRACKET;
+                    }
+                    break;
+                }
+                case '^':
+                    lookAhead = CHAR_CARET;
+                    break;
+                case '|':
+                    lookAhead = CHAR_VERTICAL_BAR;
+                    break;
+                case '.':
+                    lookAhead = CHAR_DOT;
+                    break;
+                default:
+                    break;
+                }
+            } else if (mode == Lexer.MODE_RANGE) {
+                switch (lookAhead) {
+                case '[':
+                    lookAhead = CHAR_LEFT_SQUARE_BRACKET;
+                    break;
+                case ']':
+                    lookAhead = CHAR_RIGHT_SQUARE_BRACKET;
+                    break;
+                case '^':
+                    lookAhead = CHAR_CARET;
+                    break;
+                case '&':
+                    lookAhead = CHAR_AMPERSAND;
+                    break;
+                case '-':
+                    lookAhead = CHAR_HYPHEN;
+                    break;
+                default:
+                    break;
+                }
+            }
+        } while (reread);
+    }
+
+    /**
+     * Parse character classes names and verifies correction of the syntax;
+     */
+    private String parseCharClassName() {
+        StringBuffer sb = new StringBuffer(10);
+        if (index < pattern.length - 2) {
+            // one symbol family
+            if (pattern[index] != '{') {
+                return "Is" + new String(pattern, nextIndex(), 1);
+            }
+
+            nextIndex();
+            char ch = 0;
+            while (index < pattern.length - 2
+                    && (ch = pattern[nextIndex()]) != '}') {
+                sb.append((char) ch);
+            }
+            if (ch != '}')
+                throw new PatternSyntaxException(I18n
+                        .getMessage("Unclosed character family"), this
+                        .toString(), index);
+        }
+
+        if (sb.length() == 0)
+            throw new PatternSyntaxException(I18n
+                    .getMessage("Empty character family"), this.toString(),
+                    index);
+
+        String res = sb.toString();
+        if (res.length() == 1)
+            return "Is" + res;
+        return (res.length() > 3 && (res.startsWith("Is") || res
+                .startsWith("In"))) ? res.substring(2) : res;
+    }
+
+    /**
+     * Process given character in assumption that it's quantifier.
+     */
+    private Quantifier processQuantifier(int ch) {
+        StringBuffer sb = new StringBuffer(4);
+        int min = -1;
+        int max = Integer.MAX_VALUE;
+        while (index < pattern.length && (ch = pattern[nextIndex()]) != '}') {
+            if (ch == ',' && min < 0) {
+                try {
+                    min = Integer.parseInt(sb.toString(), 10);
+                    sb.delete(0, sb.length());
+                } catch (NumberFormatException nfe) {
+                    throw new PatternSyntaxException(I18n
+                            .getMessage("Incorrect Quantifier Syntax"), this
+                            .toString(), index);
+                }
+            } else {
+                sb.append((char) ch);
+            }
+        }
+        if (ch != '}') {
+            throw new PatternSyntaxException(I18n
+                    .getMessage("Incorrect Quantifier Syntax"),
+                    this.toString(), index);
+        }
+        if (sb.length() > 0) {
+            try {
+                max = Integer.parseInt(sb.toString(), 10);
+                if (min < 0)
+                    min = max;
+            } catch (NumberFormatException nfe) {
+                throw new PatternSyntaxException(I18n
+                        .getMessage("Incorrect Quantifier Syntax"), this
+                        .toString(), index);
+            }
+        } else if (min < 0) {
+            throw new PatternSyntaxException(I18n
+                    .getMessage("Incorrect Quantifier Syntax"),
+                    this.toString(), index);
+        }
+        if ((min | max | max - min) < 0) {
+            throw new PatternSyntaxException(I18n
+                    .getMessage("Incorrect Quantifier Syntax"),
+                    this.toString(), index);
+        }
+
+        char mod = (index < pattern.length) ? pattern[index] : '*';
+
+        switch (mod) {
+        case '+':
+            lookAhead = Lexer.QUANT_COMP_P;
+            nextIndex();
+            break;
+        case '?':
+            lookAhead = Lexer.QUANT_COMP_R;
+            nextIndex();
+            break;
+        default:
+            lookAhead = Lexer.QUANT_COMP;
+            break;
+        }
+        return new Quantifier(min, max);
+    }
+
+    public String toString() {
+        return orig;
+    }
+
+    /**
+     * Checks if there are any characters in the pattern.
+     * 
+     * @return true if there are no more characters in the pattern.
+     */
+    public boolean isEmpty() {
+    	return ch == 0 && lookAhead == 0 && index == patternFullLength && !isSpecial();
+    }
+
+    /**
+     * Returns true if current character is plain token.
+     */
+    public static boolean isLetter(int ch) {
+        return ch >= 0;
+    }
+
+    /**
+     * Return true if current character is letter, false otherwise; This is
+     * shortcut to static method isLetter to check the current character.
+     * 
+     * @return true if current character is letter, false otherwise
+     */
+    public boolean isLetter() {
+        return !isEmpty() && !isSpecial() && isLetter(ch);
+    }
+
+    /**
+     * Process hexadecimal integer. 
+     */
+    private int readHex(String radixName, int max) {
+        StringBuffer st = new StringBuffer(max);
+        int length = pattern.length - 2;
+        int i;
+        for (i = 0; i < max && index < length; i++) {
+            st.append((char) pattern[nextIndex()]);
+        }
+        if (i == max) {
+            try {
+                return Integer.parseInt(st.toString(), 16);
+            } catch (NumberFormatException nfe) {
+            }
+        }
+
+        throw new PatternSyntaxException(I18n.getMessage("Invalid " + radixName
+                + "escape sequence"), this.toString(), index);
+    }
+
+    /**
+     * Process octal integer.
+     */
+    private int readOctals() {
+        char ch;
+        int max = 3;
+        int i = 1;
+        int first;
+        int res;
+        int length = pattern.length - 2;
+
+        switch (first = Character.digit((ch = pattern[index]), 8)) {
+        case -1:
+            throw new PatternSyntaxException(I18n.getMessage("Invalid "
+                    + "octal escape sequence"), this.toString(), index);
+        default: {
+            if (first > 3)
+                max--;
+            nextIndex();
+            res = first;
+        }
+        }
+
+        while (i < max && index < length
+                && (first = Character.digit((ch = pattern[index]), 8)) >= 0) {
+            res = res * 8 + first;
+            nextIndex();
+            i++;
+        }
+
+        return res;
+    }
+
+    /**
+     * Process expression flags givent with (?idmsux-idmsux)
+     */
+    private int readFlags() {
+        char ch;
+        boolean pos = true;
+        int res = flags;
+        
+        while (index < pattern.length) {
+            ch = pattern[index];
+            switch (ch) {
+            case '-':
+                if (!pos) {
+                    throw new PatternSyntaxException("Illegal "
+                            + "inline construct", this.toString(), index);
+                }
+                pos = false;
+                break; 
+                
+            case 'i':
+                res = pos 
+                      ? res | Pattern.CASE_INSENSITIVE 
+                      : (res ^ Pattern.CASE_INSENSITIVE) & res;
+                break;
+                
+            case 'd':
+                res = pos
+                      ? res | Pattern.UNIX_LINES 
+                	  : (res ^ Pattern.UNIX_LINES) & res;
+                break;
+                
+            case 'm':
+                res = pos 
+                      ? res | Pattern.MULTILINE 
+                      : (res ^ Pattern.MULTILINE) & res;
+                break;
+                
+            case 's':
+                res = pos 
+                      ? res | Pattern.DOTALL 
+                      : (res ^ Pattern.DOTALL) & res;
+                break;
+                
+            case 'u':
+                res = pos 
+                      ? res | Pattern.UNICODE_CASE 
+                      : (res ^ Pattern.UNICODE_CASE) & res;
+                break;
+                
+            case 'x':
+                res = pos 
+                      ? res | Pattern.COMMENTS 
+                      : (res ^ Pattern.COMMENTS) & res;
+                break;
+                
+            case ':':
+                nextIndex();
+                return res;
+                
+            case ')':
+                nextIndex();
+                return res | (1 << 8);
+                
+            default:
+                throw new PatternSyntaxException("Illegal inline construct",
+                                               this.toString(), index);
+            }
+            nextIndex();
+        }
+        throw new PatternSyntaxException("Illegal inline construct", 
+        		                       this.toString(), index);
+    }
+
+
+    /**
+     * Returns next character index to read and moves pointer to the next one.
+     * If comments flag is on this method will skip comments and whitespaces.
+     * 
+     * The following actions are equivalent if comments flag is off ch =
+     * pattern[index++] == ch = pattern[nextIndex]
+     * 
+     * @return next character index to read.
+     */
+    private int nextIndex() {
+        prevNW = index;
+        if ((flags & Pattern.COMMENTS) != 0) {
+            skipComments();
+        } else {
+            index++;
+        }
+        return prevNW;
+    }
+
+    /**
+     * Skips comments and whitespaces
+     */
+    private int skipComments() {
+        int length = pattern.length - 2;
+        index++;
+        do {
+            while (index < length && Character.isWhitespace(pattern[index]))
+                index++;
+            if (index < length && pattern[index] == '#') {
+                index++;
+                while (index < length && !isLineSeparator(pattern[index]))
+                    index++;
+            } else
+                return index;
+        } while (true);
+    }
+
+    private boolean isLineSeparator(int ch) {
+        return (ch == '\n' || ch == '\r' || ch == '\u0085' || (ch | 1) == '\u2029');
+    }
+
+    /**
+     * Returns the curr. character index.
+     */
+    public int getIndex() {
+        return curToc;
+    }
+}

Modified: incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/Pattern.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/Pattern.java?rev=395158&r1=395157&r2=395158&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/Pattern.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/Pattern.java Wed Apr 19 00:50:10 2006
@@ -75,6 +75,8 @@
      * @com.intel.drl.spec_ref
      */
     public static final int CANON_EQ = 1 << 7;
+    
+    static final int BACK_REF_NUMBER = 10;
 
     /**
      * Current <code>pattern</code> to be compiled;
@@ -87,6 +89,16 @@
     private int flags = 0;
 
     private String pattern = null;
+    
+    /*
+     * All backreferences that may be used in pattern.
+     */
+    transient private FSet backRefs [] = new FSet [BACK_REF_NUMBER];
+    
+    /*
+     * Is true if backreferenced sets replacement is needed
+     */
+    transient private boolean needsBackRefReplacement = false;
 
     transient private int groupIndex = -1;
 
@@ -191,13 +203,13 @@
         this.lexemes = new Lexer(regex, flags);
         this.flags = flags;
 
-        start = processExpression(-1, flags, null);
+        start = processExpression(-1, this.flags, null);
         if (!lexemes.isEmpty()) {
             throw new PatternSyntaxException(I18n
                     .getMessage("Trailing characters"), lexemes.toString(),
                     lexemes.getIndex());
         }
-
+        finalizeCompile();
         return this;
     }
 
@@ -227,107 +239,123 @@
     /**
      * E->AE; E->S|E; E->S; A->(a|)+ E->S(|S)*
      */
-    private AbstractSet processExpression(int ch, int new_flags,
+    private AbstractSet processExpression(int ch, int newFlags,
             AbstractSet last) {
         ArrayList children = new ArrayList();
         AbstractSet child;
-        int safe_flags = flags;
+        int saveFlags = flags;
         FSet fSet;
+        boolean saveChangedFlags = false;
 
-        if (new_flags != flags) {
-            flags = new_flags;
-            lexemes.setFlags(flags);
+        if (newFlags != flags) {
+            flags = newFlags;
         }
 
         switch (ch) {
-        case Lexer.CHAR_NONCAP_GROUP: {
+        case Lexer.CHAR_NONCAP_GROUP:
             fSet = new NonCapFSet(++consCount);
             break;
-        }
-
+        
         case Lexer.CHAR_POS_LOOKAHEAD:
-        case Lexer.CHAR_NEG_LOOKAHEAD: {
+        	/* falls through */
+        	
+        case Lexer.CHAR_NEG_LOOKAHEAD:
             fSet = new AheadFSet();
             break;
-        }
+        
         case Lexer.CHAR_POS_LOOKBEHIND:
-        case Lexer.CHAR_NEG_LOOKBEHIND: {
+        	/* falls through */
+        	
+        case Lexer.CHAR_NEG_LOOKBEHIND: 
             fSet = new BehindFSet(++consCount);
             break;
-        }
-
-        case Lexer.CHAR_ATOMIC_GROUP: {
+        
+        case Lexer.CHAR_ATOMIC_GROUP: 
             fSet = new AtomicFSet(++consCount);
             break;
-        }
-
-        default: {
+        
+        default: 
             globalGroupIndex++;
             if (last == null) {
-                fSet = new FinalSet();
-                // expr = new StartSet();
+                
+            	// expr = new StartSet();
+            	fSet = new FinalSet();
+            	saveChangedFlags = true;
             } else {
-                fSet = new FSet(globalGroupIndex);
-                // expr = new JointSet(globalGroupIndex);
+                
+            	// expr = new JointSet(globalGroupIndex);
+            	fSet = new FSet(globalGroupIndex);         
             }
-        }
+            if (globalGroupIndex > -1 && globalGroupIndex < 10) {
+            	backRefs[globalGroupIndex] = fSet;
+            }
+            break;
         }
 
         do {
             if (lexemes.isLetter()
                     && lexemes.lookAhead() == Lexer.CHAR_VERTICAL_BAR) {
                 child = processAlternations(fSet);
+            } else if (lexemes.peek() == Lexer.CHAR_VERTICAL_BAR){
+                child = new EmptySet(fSet);
+                lexemes.next();
             } else {
                 child = processSubExpression(fSet);
-                if (lexemes.peek() == Lexer.CHAR_VERTICAL_BAR)
+                if (lexemes.peek() == Lexer.CHAR_VERTICAL_BAR) {
                     lexemes.next();
+                }
             }
-            if (child != null)
-                children.add(child);
-            // expr.addChild(child);
-        } while (!(lexemes.isEmpty() || lexemes.peek() == Lexer.CHAR_RIGHT_PARENTHESIS));
-
-        if (flags != safe_flags) {
-            flags = safe_flags;
-            lexemes.setFlags(flags);
+            if (child != null) {
+                
+                //expr.addChild(child);
+            	children.add(child);                
+            }
+        } while (!(lexemes.isEmpty() 
+        		   || (lexemes.peek() == Lexer.CHAR_RIGHT_PARENTHESIS)));
+        
+        if (lexemes.back() == Lexer.CHAR_VERTICAL_BAR) {
+        	children.add(new EmptySet(fSet));
+        }
+        
+        if (flags != saveFlags && !saveChangedFlags) {
+            flags = saveFlags;
+            lexemes.restoreFlags(flags);
         }
 
         switch (ch) {
-        case Lexer.CHAR_NONCAP_GROUP: {
+        case Lexer.CHAR_NONCAP_GROUP:
             return new NonCapJointSet(children, fSet);
-        }
-        case Lexer.CHAR_POS_LOOKAHEAD: {
-            return new PositiveLookAhead(children, fSet);
-        }
+        
+        case Lexer.CHAR_POS_LOOKAHEAD:
+            return new PositiveLookAhead(children, fSet);           
 
-        case Lexer.CHAR_NEG_LOOKAHEAD: {
+        case Lexer.CHAR_NEG_LOOKAHEAD: 
             return new NegativeLookAhead(children, fSet);
-        }
-
-        case Lexer.CHAR_POS_LOOKBEHIND: {
+        
+        case Lexer.CHAR_POS_LOOKBEHIND:
             return new PositiveLookBehind(children, fSet);
-        }
-
-        case Lexer.CHAR_NEG_LOOKBEHIND: {
+        
+        case Lexer.CHAR_NEG_LOOKBEHIND:
             return new NegativeLookBehind(children, fSet);
-        }
-
-        case Lexer.CHAR_ATOMIC_GROUP: {
+        
+        case Lexer.CHAR_ATOMIC_GROUP:
             return new AtomicJointSet(children, fSet);
-        }
-        default: {
+            
+        default: 
             switch (children.size()) {
             case 0:
                 return new EmptySet(fSet);
+                
             case 1:
                 return new SingleSet((AbstractSet) children.get(0), fSet);
+                
             default:
                 return new JointSet(children, fSet);
             }
         }
-        }
     }
 
+
     /**
      * T->a+
      */
@@ -363,13 +391,22 @@
         if (lexemes.isLetter() && !lexemes.isNextSpecial()
                 && Lexer.isLetter(lexemes.lookAhead())) {
             cur = processSequence(last);
+        } else if (lexemes.peek() == Lexer.CHAR_RIGHT_PARENTHESIS) {
+        	if (last instanceof FinalSet) {
+        	    throw new PatternSyntaxException(I18n
+        	      .getMessage("unmatched )"), lexemes.toString(), 
+        	         lexemes.getIndex());
+        	} else {
+        	      cur = new EmptySet(last);
+        	}
         } else {
             cur = processQuantifier(last);
         }
 
         if (!lexemes.isEmpty()
         // && !pattern.isQuantifier()
-                && lexemes.peek() != Lexer.CHAR_RIGHT_PARENTHESIS
+                && (lexemes.peek() != Lexer.CHAR_RIGHT_PARENTHESIS 
+                		|| last instanceof FinalSet)
                 && lexemes.peek() != Lexer.CHAR_VERTICAL_BAR) {
             AbstractSet next = processSubExpression(last);
             if (cur instanceof LeafQuantifierSet
@@ -406,8 +443,6 @@
      */
     private AbstractSet processQuantifier(AbstractSet last) {
         AbstractSet term = processTerminal(last);
-        SpecialToken quantifier = null;
-
         int quant = lexemes.peek();
 
         if (term != null && !(term instanceof LeafSet)) {
@@ -578,24 +613,24 @@
         do {
             ch = lexemes.peek();
             if ((ch & 0x8000ffff) == Lexer.CHAR_LEFT_PARENTHESIS) {
-                lexemes.next();
-                int new_flags = (ch & 0x00ff0000) >> 16;
-                ch = ch & 0xff00ffff;
-
-                if (ch == Lexer.CHAR_FLAGS) {
-                    flags = new_flags;
-                    lexemes.setFlags(new_flags);
-                } else {
-                    new_flags = (ch == Lexer.CHAR_NONCAP_GROUP) ? new_flags
-                            : flags;
-                    term = processExpression(ch, new_flags, last);
-                    if (lexemes.peek() != Lexer.CHAR_RIGHT_PARENTHESIS)
-                        throw new PatternSyntaxException(I18n
-                                .getMessage("unmatched ("), lexemes.toString(),
-                                lexemes.getIndex()-1);
-                    lexemes.next();
-                }
-
+            	 int newFlags;             	
+             	 lexemes.next();
+                 newFlags = (ch & 0x00ff0000) >> 16;
+                 ch = ch & 0xff00ffff;
+                 if (ch == Lexer.CHAR_FLAGS) {
+                     flags = newFlags;
+                 } else {
+                     newFlags = (ch == Lexer.CHAR_NONCAP_GROUP) 
+                                 ? newFlags
+                                 : flags;
+                     term = processExpression(ch, newFlags, last);
+                     if (lexemes.peek() != Lexer.CHAR_RIGHT_PARENTHESIS) {
+                         throw new PatternSyntaxException(I18n
+                                 .getMessage("unmatched ("), lexemes.toString(),
+                                 lexemes.getIndex());
+                     }
+                     lexemes.next();
+                 }
             } else
                 switch (ch) {
                 case Lexer.CHAR_LEFT_SQUARE_BRACKET: {
@@ -718,6 +753,8 @@
                         } else {
                             term = new UCIBackReferenceSet(number, consCount);
                         }
+                        (backRefs [number]).isBackReferenced = true;
+                        needsBackRefReplacement = true;
                         break;
                     } else {
                         throw new PatternSyntaxException(I18n
@@ -733,6 +770,9 @@
                         term = new RangeSet(cc);
                     } else if (!lexemes.isEmpty()) {
                         term = new CharSet((char) ch);
+                    } else {
+                    	term = new EmptySet(last);
+                        break;
                     }
                     lexemes.next();
                     break;
@@ -754,6 +794,16 @@
                             term = new CharSet((char) ch);
                         }
                         lexemes.next();
+                    } else if (ch == Lexer.CHAR_VERTICAL_BAR) {
+                    	term = new EmptySet(last);
+                    } else if (ch == Lexer.CHAR_RIGHT_PARENTHESIS) {
+                        if (last instanceof FinalSet) {
+                        	throw new PatternSyntaxException(I18n
+                    				.getMessage("unmatched )"), lexemes.toString(), 
+                    		    	lexemes.getIndex());
+                        } else {
+                    	    term = new EmptySet(last);
+                        }
                     } else {
                         throw new PatternSyntaxException(I18n
                                 .getMessage("Dangling meta construction")
@@ -785,14 +835,12 @@
         CharClass res = new CharClass(alt, hasFlag(Pattern.CASE_INSENSITIVE),
                 hasFlag(Pattern.UNICODE_CASE));
         int buffer = -1;
-        // TODO remove this one, being used for debug only
-        int ch = 0;
         boolean intersection = false;
         boolean notClosed = false;
         boolean firstInClass = true;
 
         while (!lexemes.isEmpty()
-                && (notClosed = (ch = lexemes.peek()) != Lexer.CHAR_RIGHT_SQUARE_BRACKET
+                && (notClosed = (lexemes.peek()) != Lexer.CHAR_RIGHT_SQUARE_BRACKET
                         || firstInClass)) {
             switch (lexemes.peek()) {
 
@@ -917,6 +965,21 @@
         return compile(pattern, 0);
     }
 
+    /*
+     * This method do traverses of
+     * automata to finish compilation.
+     */
+    private void finalizeCompile() {
+    	
+    	/*
+    	 * Processing second pass
+    	 */    	
+    	if (needsBackRefReplacement) { //|| needsReason1 || needsReason2) {
+    		start.processSecondPass();
+    	}
+    	
+    }
+    
     /**
      * @com.intel.drl.spec_ref
      */

Modified: incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/QuantifierSet.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/QuantifierSet.java?rev=395158&r1=395157&r2=395158&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/QuantifierSet.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/QuantifierSet.java Wed Apr 19 00:50:10 2006
@@ -1,62 +1,133 @@
-/*
- *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-/**
- * @author Nikolay A. Kuznetsov
- * @version $Revision: 1.14.2.2 $
- */
-package java.util.regex;
-
-/**
- * Base class for quantifiers.
- * 
- * @author Nikolay A. Kuznetsov
- * @version $Revision: 1.14.2.2 $
- */
-abstract class QuantifierSet extends AbstractSet {
-    
-    protected AbstractSet innerSet;
-
-    public QuantifierSet(AbstractSet innerSet, AbstractSet next, int type) {
-        super(next);
-        this.innerSet = innerSet;
-        setType(type);
-    }
-
-    /**
-     * Returns the innerSet.
-     */
-    public AbstractSet getInnerSet() {
-        return innerSet;
-    }
-
-    /**
-     * Sets an inner set.
-     * @param innerSet
-     *            The innerSet to set.
-     */
-    public void setInnerSet(AbstractSet innerSet) {
-        this.innerSet = innerSet;
-    }
-
-    public boolean first(AbstractSet set) {
-        return innerSet.first(set) || next.first(set);
-    }
-
-    public boolean hasConsumed(MatchResultImpl mr) {
-        return true;
-    }
-}
+/*
+ *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Nikolay A. Kuznetsov
+ * @version $Revision: 1.14.2.2 $
+ */
+package java.util.regex;
+
+/**
+ * Base class for quantifiers.
+ * 
+ * @author Nikolay A. Kuznetsov
+ * @version $Revision: 1.14.2.2 $
+ */
+abstract class QuantifierSet extends AbstractSet {
+    
+    protected AbstractSet innerSet;
+
+    public QuantifierSet(AbstractSet innerSet, AbstractSet next, int type) {
+        super(next);
+        this.innerSet = innerSet;
+        setType(type);
+    }
+
+    /**
+     * Returns the innerSet.
+     */
+    public AbstractSet getInnerSet() {
+        return innerSet;
+    }
+
+    /**
+     * Sets an inner set.
+     * @param innerSet
+     *            The innerSet to set.
+     */
+    public void setInnerSet(AbstractSet innerSet) {
+        this.innerSet = innerSet;
+    }
+
+    public boolean first(AbstractSet set) {
+        return innerSet.first(set) || next.first(set);
+    }
+
+    public boolean hasConsumed(MatchResultImpl mr) {
+        return true;
+    }
+    
+    /**
+     * This method is used for traversing nodes after the 
+     * first stage of compilation.
+     */
+    public void processSecondPass() {
+    	this.isSecondPassVisited = true;
+    	
+    	if (next != null) {
+    	    
+    		if (!next.isSecondPassVisited) {
+    		    
+    			/*
+    	         * Add here code to do during the pass
+    	         */
+    	        JointSet set = next.processBackRefReplacement();
+    	
+    	        if (set != null) {
+    	            next.isSecondPassVisited = true;
+    	            next =(AbstractSet) set;
+    	        }
+    	        
+    	        /*
+    	         * End code to do during the pass
+    	         */
+    		    next.processSecondPass();
+    	    } 
+    	}
+    	
+    	if (innerSet != null) {
+    		
+    		if (!innerSet.isSecondPassVisited) {
+    			
+    			/*
+    	         * Add here code to do during the pass
+    	         */
+    	        JointSet set = innerSet.processBackRefReplacement();
+    	
+    	        if (set != null) {
+    	        	innerSet.isSecondPassVisited = true;
+    	        	innerSet =(AbstractSet) set;
+    	        }
+    	        
+    	        /*
+    	         * End code to do during the pass
+    	         */
+    	        innerSet.processSecondPass();
+    		} else {
+    			
+    			/*
+    	    	 * We reach node through innerSet but it is already traversed.
+    	    	 * You can see this situation for GroupQuantifierSet.innerset
+    	    	 * if we compile smth like "(a)+ when 
+    	    	 * GroupQuantifierSet == GroupQuantifierSet.innerset.fSet.next
+    	    	 */
+    			 
+    			/*
+    	         * Add here code to do during the pass
+    	         */
+    			if (innerSet instanceof SingleSet 
+    					&& ((FSet) ((JointSet) innerSet).fSet)
+    					    .isBackReferenced) {    				
+    	    		innerSet = innerSet.next;
+    			}
+    			
+    			/*
+    	         * End code to do during the pass
+    	         */    			
+    		}
+    	}
+    }
+}

Modified: incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/SingleSet.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/SingleSet.java?rev=395158&r1=395157&r2=395158&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/SingleSet.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/regex/src/main/java/java/util/regex/SingleSet.java Wed Apr 19 00:50:10 2006
@@ -1,69 +1,127 @@
-/*
- *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-/**
- * @author Nikolay A. Kuznetsov
- * @version $Revision: 1.8.2.2 $
- */
-package java.util.regex;
-
-/**
- * Group node over subexpression w/o alternations.
- * @author Nikolay A. Kuznetsov
- * @version $Revision: 1.8.2.2 $
- */
-class SingleSet extends JointSet {
-    
-    private AbstractSet kid;
-
-    public SingleSet(AbstractSet child, FSet fSet) {
-        this.kid = child;
-        this.fSet = fSet;
-        this.groupIndex = fSet.getGroupIndex();
-    }
-
-    public int matches(int stringIndex, CharSequence testString,
-            MatchResultImpl matchResult) {
-        int start = matchResult.getStart(groupIndex);
-        matchResult.setStart(groupIndex, stringIndex);
-        int shift = kid.matches(stringIndex, testString, matchResult);
-        if (shift >= 0) {
-            return shift;
-        }
-        matchResult.setStart(groupIndex, start);
-        return -1;
-    }
-
-    public int find(int stringIndex, CharSequence testString,
-            MatchResultImpl matchResult) {
-        int res = kid.find(stringIndex, testString, matchResult);
-        if (res >= 0)
-            matchResult.setStart(groupIndex, res);
-        return res;
-    }
-
-    public int findBack(int stringIndex, int lastIndex,
-            CharSequence testString, MatchResultImpl matchResult) {
-        int res = kid.findBack(stringIndex, lastIndex, testString, matchResult);
-        if (res >= 0)
-            matchResult.setStart(groupIndex, res);
-        return res;
-    }
-
-    public boolean first(AbstractSet set) {
-        return kid.first(set);
-    }
-}
+/*
+ *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Nikolay A. Kuznetsov
+ * @version $Revision: 1.8.2.2 $
+ */
+package java.util.regex;
+
+/**
+ * Group node over subexpression w/o alternations.
+ * @author Nikolay A. Kuznetsov
+ * @version $Revision: 1.8.2.2 $
+ */
+class SingleSet extends JointSet {
+    
+    protected AbstractSet kid;
+
+    public SingleSet(AbstractSet child, FSet fSet) {
+        this.kid = child;
+        this.fSet = fSet;
+        this.groupIndex = fSet.getGroupIndex();
+    }
+
+    public int matches(int stringIndex, CharSequence testString,
+            MatchResultImpl matchResult) {
+        int start = matchResult.getStart(groupIndex);
+        matchResult.setStart(groupIndex, stringIndex);
+        int shift = kid.matches(stringIndex, testString, matchResult);
+        if (shift >= 0) {
+            return shift;
+        }
+        matchResult.setStart(groupIndex, start);
+        return -1;
+    }
+
+    public int find(int stringIndex, CharSequence testString,
+            MatchResultImpl matchResult) {
+        int res = kid.find(stringIndex, testString, matchResult);
+        if (res >= 0)
+            matchResult.setStart(groupIndex, res);
+        return res;
+    }
+
+    public int findBack(int stringIndex, int lastIndex,
+            CharSequence testString, MatchResultImpl matchResult) {
+        int res = kid.findBack(stringIndex, lastIndex, testString, matchResult);
+        if (res >= 0)
+            matchResult.setStart(groupIndex, res);
+        return res;
+    }
+
+    public boolean first(AbstractSet set) {
+        return kid.first(set);
+    }
+    
+    /**
+     * This method is used for replacement backreferenced
+     * sets.
+     */
+    public JointSet processBackRefReplacement() {
+        BackReferencedSingleSet set = new BackReferencedSingleSet(this);
+    	
+        /*
+         * We will store a reference to created BackReferencedSingleSet
+         * in next field. This is needed toprocess replacement
+         * of sets correctly since sometimes we cannot renew all references to
+         * detachable set in the current point of traverse. See
+         * QuantifierSet and AbstractSet processSecondPass() methods for
+         * more details.
+         */
+        next = set;
+        return set;
+    }
+    
+    /**
+     * This method is used for traversing nodes after the 
+     * first stage of compilation.
+     */
+    public void processSecondPass() {
+    	this.isSecondPassVisited = true;
+    	    
+        if (fSet != null && !fSet.isSecondPassVisited) {
+    		    
+  		   /*
+   	        * Add here code to do during the pass
+            */
+    	       
+    	   /*
+    	    * End code to do during the pass
+    	    */
+    	   fSet.processSecondPass();
+    	} 
+    	
+        if (kid != null && !kid.isSecondPassVisited) {
+        	
+           /*
+    	    * Add here code to do during the pass
+            */     	   
+           JointSet set = kid.processBackRefReplacement();
+        
+           if (set != null) {
+        	   kid.isSecondPassVisited = true;
+        	   kid = (AbstractSet) set;
+           }
+           
+           /*
+     	    * End code to do during the pass
+     	    */
+     	   
+           kid.processSecondPass();
+        }
+    }
+}