Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
    *
    * This Source Code Form is subject to the terms of the Mozilla Public
    * License, v. 2.0. If a copy of the MPL was not distributed with this
    * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   
   package org.mozilla.javascript;
   
   import java.io.*;

This class implements the JavaScript scanner. It is based on the C source files jsscan.c and jsscan.h in the jsref package.

Author(s):
Mike McCabe
Brendan Eich
See also:
Parser
  
  
  class TokenStream
  {
      /*
       * For chars - because we need something out-of-range
       * to check.  (And checking EOF by exception is annoying.)
       * Note distinction from EOF token type!
       */
      private final static int
          EOF_CHAR = -1;
  
      private final static char BYTE_ORDER_MARK = '\uFEFF';
  
      TokenStream(Parser parserReader sourceReaderString sourceString,
                  int lineno)
      {
          this. = parser;
          this. = lineno;
          if (sourceReader != null) {
              if (sourceString != null) Kit.codeBug();
              this. = sourceReader;
              this. = new char[512];
              this. = 0;
          } else {
              if (sourceString == null) Kit.codeBug();
              this. = sourceString;
              this. = sourceString.length();
          }
          this. = this. = 0;
      }
  
      /* This function uses the cached op, string and number fields in
       * TokenStream; if getToken has been called since the passed token
       * was scanned, the op or string printed may be incorrect.
       */
      String tokenToString(int token)
      {
          if (.) {
              String name = Token.name(token);
  
              switch (token) {
              case .:
              case .:
              case .:
                  return name + " `" + this. + "'";
  
              case .:
                  return "NUMBER " + this.;
              }
  
              return name;
          }
          return "";
      }
  
      static boolean isKeyword(String s)
      {
          return . != stringToKeyword(s);
      }
  
      private static int stringToKeyword(String name)
      {
  // #string_id_map#
  // The following assumes that Token.EOF == 0
          final int
              Id_break         = .,
              Id_case          = .,
              Id_continue      = .,
              Id_default       = .,
              Id_delete        = .,
              Id_do            = .,
              Id_else          = .,
              Id_export        = .,
              Id_false         = .,
              Id_for           = .,
              Id_function      = .,
              Id_if            = .,
              Id_in            = .,
             Id_let           = .,  // reserved ES5 strict
             Id_new           = .,
             Id_null          = .,
             Id_return        = .,
             Id_switch        = .,
             Id_this          = .,
             Id_true          = .,
             Id_typeof        = .,
             Id_var           = .,
             Id_void          = .,
             Id_while         = .,
             Id_with          = .,
             Id_yield         = .,  // reserved ES5 strict
 
             // the following are #ifdef RESERVE_JAVA_KEYWORDS in jsscan.c
             Id_abstract      = .,  // ES3 only
             Id_boolean       = .,  // ES3 only
             Id_byte          = .,  // ES3 only
             Id_catch         = .,
             Id_char          = .,  // ES3 only
             Id_class         = .,
             Id_const         = .,     // reserved
             Id_debugger      = .,
             Id_double        = .,  // ES3 only
             Id_enum          = .,
             Id_extends       = .,
             Id_final         = .,  // ES3 only
             Id_finally       = .,
             Id_float         = .,  // ES3 only
             Id_goto          = .,  // ES3 only
             Id_implements    = .,  // ES3, ES5 strict
             Id_import        = .,
             Id_instanceof    = .,
             Id_int           = .,  // ES3
             Id_interface     = .,  // ES3, ES5 strict
             Id_long          = .,  // ES3 only
             Id_native        = .,  // ES3 only
             Id_package       = .,  // ES3, ES5 strict
             Id_private       = .,  // ES3, ES5 strict
             Id_protected     = .,  // ES3, ES5 strict
             Id_public        = .,  // ES3, ES5 strict
             Id_short         = .,  // ES3 only
             Id_static        = .,  // ES3, ES5 strict
             Id_super         = .,
             Id_synchronized  = .,  // ES3 only
             Id_throw         = .,
             Id_throws        = .,  // ES3 only
             Id_transient     = .,  // ES3 only
             Id_try           = .,
             Id_volatile      = .;  // ES3 only
 
         int id;
         String s = name;
 // #generated# Last update: 2007-04-18 13:53:30 PDT
         L0: { id = 0; String X = nullint c;
             L: switch (s.length()) {
             case 2: c=s.charAt(1);
                 if (c=='f') { if (s.charAt(0)=='i') {id=Id_ifbreak L0;} }
                 else if (c=='n') { if (s.charAt(0)=='i') {id=Id_inbreak L0;} }
                 else if (c=='o') { if (s.charAt(0)=='d') {id=Id_dobreak L0;} }
                 break L;
             case 3: switch (s.charAt(0)) {
                 case 'f'if (s.charAt(2)=='r' && s.charAt(1)=='o') {id=Id_forbreak L0;} break L;
                 case 'i'if (s.charAt(2)=='t' && s.charAt(1)=='n') {id=Id_intbreak L0;} break L;
                 case 'l'if (s.charAt(2)=='t' && s.charAt(1)=='e') {id=Id_letbreak L0;} break L;
                 case 'n'if (s.charAt(2)=='w' && s.charAt(1)=='e') {id=Id_newbreak L0;} break L;
                 case 't'if (s.charAt(2)=='y' && s.charAt(1)=='r') {id=Id_trybreak L0;} break L;
                 case 'v'if (s.charAt(2)=='r' && s.charAt(1)=='a') {id=Id_varbreak L0;} break L;
                 } break L;
             case 4: switch (s.charAt(0)) {
                 case 'b'X="byte";id=Id_bytebreak L;
                 case 'c'c=s.charAt(3);
                     if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='a') {id=Id_casebreak L0;} }
                     else if (c=='r') { if (s.charAt(2)=='a' && s.charAt(1)=='h') {id=Id_charbreak L0;} }
                     break L;
                 case 'e'c=s.charAt(3);
                     if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='l') {id=Id_elsebreak L0;} }
                     else if (c=='m') { if (s.charAt(2)=='u' && s.charAt(1)=='n') {id=Id_enumbreak L0;} }
                     break L;
                 case 'g'X="goto";id=Id_gotobreak L;
                 case 'l'X="long";id=Id_longbreak L;
                 case 'n'X="null";id=Id_nullbreak L;
                 case 't'c=s.charAt(3);
                     if (c=='e') { if (s.charAt(2)=='u' && s.charAt(1)=='r') {id=Id_truebreak L0;} }
                     else if (c=='s') { if (s.charAt(2)=='i' && s.charAt(1)=='h') {id=Id_thisbreak L0;} }
                     break L;
                 case 'v'X="void";id=Id_voidbreak L;
                 case 'w'X="with";id=Id_withbreak L;
                 } break L;
             case 5: switch (s.charAt(2)) {
                 case 'a'X="class";id=Id_classbreak L;
                 case 'e'c=s.charAt(0);
                     if (c=='b') { X="break";id=Id_break; }
                     else if (c=='y') { X="yield";id=Id_yield; }
                     break L;
                 case 'i'X="while";id=Id_whilebreak L;
                 case 'l'X="false";id=Id_falsebreak L;
                 case 'n'c=s.charAt(0);
                     if (c=='c') { X="const";id=Id_const; }
                     else if (c=='f') { X="final";id=Id_final; }
                     break L;
                 case 'o'c=s.charAt(0);
                     if (c=='f') { X="float";id=Id_float; }
                     else if (c=='s') { X="short";id=Id_short; }
                     break L;
                 case 'p'X="super";id=Id_superbreak L;
                 case 'r'X="throw";id=Id_throwbreak L;
                 case 't'X="catch";id=Id_catchbreak L;
                 } break L;
             case 6: switch (s.charAt(1)) {
                 case 'a'X="native";id=Id_nativebreak L;
                 case 'e'c=s.charAt(0);
                     if (c=='d') { X="delete";id=Id_delete; }
                     else if (c=='r') { X="return";id=Id_return; }
                     break L;
                 case 'h'X="throws";id=Id_throwsbreak L;
                 case 'm'X="import";id=Id_importbreak L;
                 case 'o'X="double";id=Id_doublebreak L;
                 case 't'X="static";id=Id_staticbreak L;
                 case 'u'X="public";id=Id_publicbreak L;
                 case 'w'X="switch";id=Id_switchbreak L;
                 case 'x'X="export";id=Id_exportbreak L;
                 case 'y'X="typeof";id=Id_typeofbreak L;
                 } break L;
             case 7: switch (s.charAt(1)) {
                 case 'a'X="package";id=Id_packagebreak L;
                 case 'e'X="default";id=Id_defaultbreak L;
                 case 'i'X="finally";id=Id_finallybreak L;
                 case 'o'X="boolean";id=Id_booleanbreak L;
                 case 'r'X="private";id=Id_privatebreak L;
                 case 'x'X="extends";id=Id_extendsbreak L;
                 } break L;
             case 8: switch (s.charAt(0)) {
                 case 'a'X="abstract";id=Id_abstractbreak L;
                 case 'c'X="continue";id=Id_continuebreak L;
                 case 'd'X="debugger";id=Id_debuggerbreak L;
                 case 'f'X="function";id=Id_functionbreak L;
                 case 'v'X="volatile";id=Id_volatilebreak L;
                 } break L;
             case 9: c=s.charAt(0);
                 if (c=='i') { X="interface";id=Id_interface; }
                 else if (c=='p') { X="protected";id=Id_protected; }
                 else if (c=='t') { X="transient";id=Id_transient; }
                 break L;
             case 10: c=s.charAt(1);
                 if (c=='m') { X="implements";id=Id_implements; }
                 else if (c=='n') { X="instanceof";id=Id_instanceof; }
                 break L;
             case 12: X="synchronized";id=Id_synchronizedbreak L;
             }
             if (X!=null && X!=s && !X.equals(s)) id = 0;
         }
 // #/generated#
 // #/string_id_map#
         if (id == 0) { return .; }
         return id & 0xff;
     }
 
     final String getSourceString() { return ; }
 
     final int getLineno() { return ; }
 
     final String getString() { return ; }
 
     final char getQuoteChar() {
         return (char;
     }
 
     final double getNumber() { return ; }
     final boolean isNumberOctal() { return ; }
     final boolean isNumberHex() { return ; }
 
     final boolean eof() { return ; }
 
     final int getToken() throws IOException
     {
         int c;
 
     retry:
         for (;;) {
             // Eat whitespace, possibly sensitive to newlines.
             for (;;) {
                 c = getChar();
                 if (c == ) {
                      =  - 1;
                      = ;
                     return .;
                 } else if (c == '\n') {
                      = false;
                      =  - 1;
                      = ;
                     return .;
                 } else if (!isJSSpace(c)) {
                     if (c != '-') {
                          = true;
                     }
                     break;
                 }
             }
 
             // Assume the token will be 1 char - fixed up below.
              =  - 1;
              = ;
 
             if (c == '@'return .;
 
             // identifier/keyword/instanceof?
             // watch out for starting with a <backslash>
             boolean identifierStart;
             boolean isUnicodeEscapeStart = false;
             if (c == '\\') {
                 c = getChar();
                 if (c == 'u') {
                     identifierStart = true;
                     isUnicodeEscapeStart = true;
                      = 0;
                 } else {
                     identifierStart = false;
                     ungetChar(c);
                     c = '\\';
                 }
             } else {
                 identifierStart = Character.isJavaIdentifierStart((char)c);
                 if (identifierStart) {
                      = 0;
                     addToString(c);
                 }
             }
 
             if (identifierStart) {
                 boolean containsEscape = isUnicodeEscapeStart;
                 for (;;) {
                     if (isUnicodeEscapeStart) {
                         // strictly speaking we should probably push-back
                         // all the bad characters if the <backslash>uXXXX
                         // sequence is malformed. But since there isn't a
                         // correct context(is there?) for a bad Unicode
                         // escape sequence in an identifier, we can report
                         // an error here.
                         int escapeVal = 0;
                         for (int i = 0; i != 4; ++i) {
                             c = getChar();
                             escapeVal = Kit.xDigitToInt(cescapeVal);
                             // Next check takes care about c < 0 and bad escape
                             if (escapeVal < 0) { break; }
                         }
                         if (escapeVal < 0) {
                             .addError("msg.invalid.escape");
                             return .;
                         }
                         addToString(escapeVal);
                         isUnicodeEscapeStart = false;
                     } else {
                         c = getChar();
                         if (c == '\\') {
                             c = getChar();
                             if (c == 'u') {
                                 isUnicodeEscapeStart = true;
                                 containsEscape = true;
                             } else {
                                 .addError("msg.illegal.character");
                                 return .;
                             }
                         } else {
                             if (c ==  || c == 
                                 || !Character.isJavaIdentifierPart((char)c))
                             {
                                 break;
                             }
                             addToString(c);
                         }
                     }
                 }
                 ungetChar(c);
 
                 String str = getStringFromBuffer();
                 if (!containsEscape) {
                     // OPT we shouldn't have to make a string (object!) to
                     // check if it's a keyword.
 
                     // Return the corresponding token if it's a keyword
                     int result = stringToKeyword(str);
                     if (result != .) {
                         if ((result == . || result == .) &&
                             ..getLanguageVersion()
                                < .)
                         {
                             // LET and YIELD are tokens only in 1.7 and later
                              = result == . ? "let" : "yield";
                             result = .;
                         }
                         // Save the string in case we need to use in
                         // object literal definitions.
                         this. = (String).intern(str);
                         if (result != .) {
                             return result;
                         } else if (!..
                                         isReservedKeywordAsIdentifier())
                         {
                             return result;
                         }
                     }
                 } else if (isKeyword(str)) {
                     // If a string contains unicodes, and converted to a keyword,
                     // we convert the last character back to unicode
                     str = convertLastCharToHex(str);
                 }
                 this. = (String).intern(str);
                 return .;
             }
 
             // is it a number?
             if (isDigit(c) || (c == '.' && isDigit(peekChar()))) {
                  = false;
                  = 0;
                 int base = 10;
                  =  = false;
 
                 if (c == '0') {
                     c = getChar();
                     if (c == 'x' || c == 'X') {
                         base = 16;
                          = true;
                         c = getChar();
                     } else if (isDigit(c)) {
                         base = 8;
                          = true;
                     } else {
                         addToString('0');
                     }
                 }
 
                 if (base == 16) {
                     while (0 <= Kit.xDigitToInt(c, 0)) {
                         addToString(c);
                         c = getChar();
                     }
                 } else {
                     while ('0' <= c && c <= '9') {
                         /*
                          * We permit 08 and 09 as decimal numbers, which
                          * makes our behavior a superset of the ECMA
                          * numeric grammar.  We might not always be so
                          * permissive, so we warn about it.
                          */
                         if (base == 8 && c >= '8') {
                             .addWarning("msg.bad.octal.literal",
                                               c == '8' ? "8" : "9");
                             base = 10;
                         }
                         addToString(c);
                         c = getChar();
                     }
                 }
 
                 boolean isInteger = true;
 
                 if (base == 10 && (c == '.' || c == 'e' || c == 'E')) {
                     isInteger = false;
                     if (c == '.') {
                         do {
                             addToString(c);
                             c = getChar();
                         } while (isDigit(c));
                     }
                     if (c == 'e' || c == 'E') {
                         addToString(c);
                         c = getChar();
                         if (c == '+' || c == '-') {
                             addToString(c);
                             c = getChar();
                         }
                         if (!isDigit(c)) {
                             .addError("msg.missing.exponent");
                             return .;
                         }
                         do {
                             addToString(c);
                             c = getChar();
                         } while (isDigit(c));
                     }
                 }
                 ungetChar(c);
                 String numString = getStringFromBuffer();
                 this. = numString;
 
                 double dval;
                 if (base == 10 && !isInteger) {
                     try {
                         // Use Java conversion to number from string...
                         dval = Double.parseDouble(numString);
                     }
                     catch (NumberFormatException ex) {
                         .addError("msg.caught.nfe");
                         return .;
                     }
                 } else {
                     dval = ScriptRuntime.stringToNumber(numString, 0, base);
                 }
 
                 this. = dval;
                 return .;
             }
 
             // is it a string?
             if (c == '"' || c == '\'') {
                 // We attempt to accumulate a string the fast way, by
                 // building it directly out of the reader.  But if there
                 // are any escaped characters in the string, we revert to
                 // building it out of a StringBuffer.
 
                  = c;
                  = 0;
 
                 c = getChar(false);
             strLoop: while (c != ) {
                     if (c == '\n' || c == ) {
                         ungetChar(c);
                          = ;
                         .addError("msg.unterminated.string.lit");
                         return .;
                     }
 
                     if (c == '\\') {
                         // We've hit an escaped character
                         int escapeVal;
 
                         c = getChar();
                         switch (c) {
                         case 'b'c = '\b'break;
                         case 'f'c = '\f'break;
                         case 'n'c = '\n'break;
                         case 'r'c = '\r'break;
                         case 't'c = '\t'break;
 
                         // \v a late addition to the ECMA spec,
                         // it is not in Java, so use 0xb
                         case 'v'c = 0xb; break;
 
                         case 'u':
                             // Get 4 hex digits; if the u escape is not
                             // followed by 4 hex digits, use 'u' + the
                             // literal character sequence that follows.
                             int escapeStart = ;
                             addToString('u');
                             escapeVal = 0;
                             for (int i = 0; i != 4; ++i) {
                                 c = getChar();
                                 escapeVal = Kit.xDigitToInt(cescapeVal);
                                 if (escapeVal < 0) {
                                     continue strLoop;
                                 }
                                 addToString(c);
                             }
                             // prepare for replace of stored 'u' sequence
                             // by escape value
                              = escapeStart;
                             c = escapeVal;
                             break;
                         case 'x':
                             // Get 2 hex digits, defaulting to 'x'+literal
                             // sequence, as above.
                             c = getChar();
                             escapeVal = Kit.xDigitToInt(c, 0);
                             if (escapeVal < 0) {
                                 addToString('x');
                                 continue strLoop;
                             } else {
                                 int c1 = c;
                                 c = getChar();
                                 escapeVal = Kit.xDigitToInt(cescapeVal);
                                 if (escapeVal < 0) {
                                     addToString('x');
                                     addToString(c1);
                                     continue strLoop;
                                 } else {
                                     // got 2 hex digits
                                     c = escapeVal;
                                 }
                             }
                             break;
 
                         case '\n':
                             // Remove line terminator after escape to follow
                             // SpiderMonkey and C/C++
                             c = getChar();
                             continue strLoop;
 
                         default:
                             if ('0' <= c && c < '8') {
                                 int val = c - '0';
                                 c = getChar();
                                 if ('0' <= c && c < '8') {
                                     val = 8 * val + c - '0';
                                     c = getChar();
                                     if ('0' <= c && c < '8' && val <= 037) {
                                         // c is 3rd char of octal sequence only
                                         // if the resulting val <= 0377
                                         val = 8 * val + c - '0';
                                         c = getChar();
                                     }
                                 }
                                 ungetChar(c);
                                 c = val;
                             }
                         }
                     }
                     addToString(c);
                     c = getChar(false);
                 }
 
                 String str = getStringFromBuffer();
                 this. = (String).intern(str);
                 return .;
             }
 
             switch (c) {
             case ';'return .;
             case '['return .;
             case ']'return .;
             case '{'return .;
             case '}'return .;
             case '('return .;
             case ')'return .;
             case ','return .;
             case '?'return .;
             case ':':
                 if (matchChar(':')) {
                     return .;
                 } else {
                     return .;
                 }
             case '.':
                 if (matchChar('.')) {
                     return .;
                 } else if (matchChar('(')) {
                     return .;
                 } else {
                     return .;
                 }
 
             case '|':
                 if (matchChar('|')) {
                     return .;
                 } else if (matchChar('=')) {
                     return .;
                 } else {
                     return .;
                 }
 
             case '^':
                 if (matchChar('=')) {
                     return .;
                 } else {
                     return .;
                 }
 
             case '&':
                 if (matchChar('&')) {
                     return .;
                 } else if (matchChar('=')) {
                     return .;
                 } else {
                     return .;
                 }
 
             case '=':
                 if (matchChar('=')) {
                     if (matchChar('=')) {
                         return .;
                     } else {
                         return .;
                     }
                 } else {
                     return .;
                 }
 
             case '!':
                 if (matchChar('=')) {
                     if (matchChar('=')) {
                         return .;
                     } else {
                         return .;
                     }
                 } else {
                     return .;
                 }
 
             case '<':
                 /* NB:treat HTML begin-comment as comment-till-eol */
                 if (matchChar('!')) {
                     if (matchChar('-')) {
                         if (matchChar('-')) {
                              =  - 4;
                             skipLine();
                              = ..;
                             return .;
                         }
                         ungetCharIgnoreLineEnd('-');
                     }
                     ungetCharIgnoreLineEnd('!');
                 }
                 if (matchChar('<')) {
                     if (matchChar('=')) {
                         return .;
                     } else {
                         return .;
                     }
                 } else {
                     if (matchChar('=')) {
                         return .;
                     } else {
                         return .;
                     }
                 }
 
             case '>':
                 if (matchChar('>')) {
                     if (matchChar('>')) {
                         if (matchChar('=')) {
                             return .;
                         } else {
                             return .;
                         }
                     } else {
                         if (matchChar('=')) {
                             return .;
                         } else {
                             return .;
                         }
                     }
                 } else {
                     if (matchChar('=')) {
                         return .;
                     } else {
                         return .;
                     }
                 }
 
             case '*':
                 if (matchChar('=')) {
                     return .;
                 } else {
                     return .;
                 }
 
             case '/':
                 markCommentStart();
                 // is it a // comment?
                 if (matchChar('/')) {
                      =  - 2;
                     skipLine();
                      = ..;
                     return .;
                 }
                 // is it a /* or /** comment?
                 if (matchChar('*')) {
                     boolean lookForSlash = false;
                      =  - 2;
                     if (matchChar('*')) {
                         lookForSlash = true;
                          = ..;
                     } else {
                          = ..;
                     }
                     for (;;) {
                         c = getChar();
                         if (c == ) {
                              =  - 1;
                             .addError("msg.unterminated.comment");
                             return .;
                         } else if (c == '*') {
                             lookForSlash = true;
                         } else if (c == '/') {
                             if (lookForSlash) {
                                  = ;
                                 return .;
                             }
                         } else {
                             lookForSlash = false;
                              = ;
                         }
                     }
                 }
 
                 if (matchChar('=')) {
                     return .;
                 } else {
                     return .;
                 }
 
             case '%':
                 if (matchChar('=')) {
                     return .;
                 } else {
                     return .;
                 }
 
             case '~':
                 return .;
 
             case '+':
                 if (matchChar('=')) {
                     return .;
                 } else if (matchChar('+')) {
                     return .;
                 } else {
                     return .;
                 }
 
             case '-':
                 if (matchChar('=')) {
                     c = .;
                 } else if (matchChar('-')) {
                     if (!) {
                         // treat HTML end-comment after possible whitespace
                         // after line start as comment-until-eol
                         if (matchChar('>')) {
                             markCommentStart("--");
                             skipLine();
                              = ..;
                             return .;
                         }
                     }
                     c = .;
                 } else {
                     c = .;
                 }
                  = true;
                 return c;
 
             default:
                 .addError("msg.illegal.character");
                 return .;
             }
         }
     }
 
     private static boolean isAlpha(int c)
     {
         // Use 'Z' < 'a'
         if (c <= 'Z') {
             return 'A' <= c;
         } else {
             return 'a' <= c && c <= 'z';
         }
     }
 
     static boolean isDigit(int c)
     {
         return '0' <= c && c <= '9';
     }
 
     /* As defined in ECMA.  jsscan.c uses C isspace() (which allows
      * \v, I think.)  note that code in getChar() implicitly accepts
      * '\r' == \u000D as well.
      */
     static boolean isJSSpace(int c)
     {
         if (c <= 127) {
             return c == 0x20 || c == 0x9 || c == 0xC || c == 0xB;
         } else {
             return c == 0xA0 || c == 
                 || Character.getType((char)c) == .;
         }
     }
 
     private static boolean isJSFormatChar(int c)
     {
         return c > 127 && Character.getType((char)c) == .;
     }

    
Parser calls the method when it gets / or /= in literal context.
 
     void readRegExp(int startToken)
         throws IOException
     {
         int start = ;
          = 0;
         if (startToken == .) {
             // Miss-scanned /=
             addToString('=');
         } else {
             if (startToken != .) Kit.codeBug();
         }
 
         boolean inCharSet = false// true if inside a '['..']' pair
         int c;
         while ((c = getChar()) != '/' || inCharSet) {
             if (c == '\n' || c == ) {
                 ungetChar(c);
                  =  - 1;
                 this. = new String(, 0, );
                 .reportError("msg.unterminated.re.lit");
                 return;
             }
             if (c == '\\') {
                 addToString(c);
                 c = getChar();
             } else if (c == '[') {
                 inCharSet = true;
             } else if (c == ']') {
                 inCharSet = false;
             }
             addToString(c);
         }
         int reEnd = ;
 
         while (true) {
             if (matchChar('g'))
                 addToString('g');
             else if (matchChar('i'))
                 addToString('i');
             else if (matchChar('m'))
                 addToString('m');
             else if (matchChar('y'))  // FireFox 3
                 addToString('y');
             else
                 break;
         }
          = start +  + 2;  // include slashes
 
         if (isAlpha(peekChar())) {
             .reportError("msg.invalid.re.flag");
         }
 
         this. = new String(, 0, reEnd);
         this. = new String(reEnd,
                                        - reEnd);
     }
 
         String flags = this.;
         this. = null;
         return flags;
     }
 
     boolean isXMLAttribute()
     {
         return ;
     }
 
     int getFirstXMLToken() throws IOException
     {
          = 0;
          = false;
          = false;
         if (!canUngetChar())
             return .;
         ungetChar('<');
         return getNextXMLToken();
     }
 
     int getNextXMLToken() throws IOException
     {
          = ;
          = 0; // remember the XML
 
         for (int c = getChar(); c != c = getChar()) {
             if () {
                 switch (c) {
                 case '>':
                     addToString(c);
                      = false;
                      = false;
                     break;
                 case '/':
                     addToString(c);
                     if (peekChar() == '>') {
                         c = getChar();
                         addToString(c);
                          = false;
                         --;
                     }
                     break;
                 case '{':
                     ungetChar(c);
                     this. = getStringFromBuffer();
                     return .;
                 case '\'':
                 case '"':
                     addToString(c);
                     if (!readQuotedString(c)) return .;
                     break;
                 case '=':
                     addToString(c);
                      = true;
                     break;
                 case ' ':
                 case '\t':
                 case '\r':
                 case '\n':
                     addToString(c);
                     break;
                 default:
                     addToString(c);
                      = false;
                     break;
                 }
                if (! &&  == 0) {
                    this. = getStringFromBuffer();
                    return .;
                }
            } else {
                switch (c) {
                case '<':
                    addToString(c);
                    c = peekChar();
                    switch (c) {
                    case '!':
                        c = getChar(); // Skip !
                        addToString(c);
                        c = peekChar();
                        switch (c) {
                        case '-':
                            c = getChar(); // Skip -
                            addToString(c);
                            c = getChar();
                            if (c == '-') {
                                addToString(c);
                                if(!readXmlComment()) return .;
                            } else {
                                // throw away the string in progress
                                 = 0;
                                this. = null;
                                .addError("msg.XML.bad.form");
                                return .;
                            }
                            break;
                        case '[':
                            c = getChar(); // Skip [
                            addToString(c);
                            if (getChar() == 'C' &&
                                getChar() == 'D' &&
                                getChar() == 'A' &&
                                getChar() == 'T' &&
                                getChar() == 'A' &&
                                getChar() == '[')
                            {
                                addToString('C');
                                addToString('D');
                                addToString('A');
                                addToString('T');
                                addToString('A');