/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/** The lexical analyzer maps an input stream consisting of
* ASCII characters and Unicode escapes into a token sequence.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
private static boolean scannerDebug = false;
/* Output variables; set by nextToken():
*/
/** The token, set by nextToken().
*/
/** Allow hex floating-point literals.
*/
private boolean allowHexFloats;
/** Allow binary literals.
*/
private boolean allowBinaryLiterals;
/** Allow underscores in literals.
*/
private boolean allowUnderscoresInLiterals;
/** The source language setting.
*/
/** The token's position, 0-based offset from beginning of text.
*/
private int pos;
/** Character position just after the last character of the token.
*/
private int endPos;
/** The last character position of the previous token.
*/
private int prevEndPos;
/** The position where a lexical error occurred;
*/
/** The name of an identifier or token:
*/
/** The radix of a numeric literal token.
*/
private int radix;
/** Has a @deprecated been encountered in last doc comment?
* this needs to be reset by client.
*/
protected boolean deprecatedFlag = false;
/** A character buffer for literals.
*/
private int sp;
/** The input buffer, index of next chacter to be read,
* index of one past last character in buffer.
*/
private char[] buf;
private int bp;
private int buflen;
private int eofPos;
/** The current character.
*/
private char ch;
/** The buffer index of the last converted unicode character
*/
/** The log to be used for error reporting.
*/
/** The name table. */
/** The keyword table. */
/** Common code for constructors. */
}
private static boolean hexFloatsWork() {
try {
return true;
} catch (NumberFormatException ex) {
return false;
}
}
/** Create a scanner from the input buffer. buffer must implement
* array() and compact(), and remaining() must be less than limit().
*/
}
/**
* Create a scanner from the input array. This method might
* modify the array. To avoid copying the input array, ensure
* that {@code inputLength < input.length} or
* {@code input[input.length -1]} is a white space character.
*
* @param fac the factory which created this Scanner
* @param input the input, might be modified
* @param inputLength the size of the input.
* Must be positive and less than or equal to input.length.
*/
this(fac);
inputLength--;
} else {
}
}
bp = -1;
scanChar();
}
/** Report an error at the given position using the provided arguments.
*/
}
/** Report an error at the current token position using the provided
* arguments.
*/
}
/** Convert an ASCII digit from its base (8, 10, or 16)
* to its value.
*/
char c = ch;
}
return result;
}
/** Convert unicode escape; bp points to initial '\' character
* (Spec 3.3).
*/
private void convertUnicode() {
if (ch == 'u') {
do {
} while (ch == 'u');
int d = digit(16);
int code = d;
d = digit(16);
}
if (d >= 0) {
return;
}
}
} else {
bp--;
ch = '\\';
}
}
}
/** Read next character.
*/
private void scanChar() {
if (ch == '\\') {
}
}
/** Read next character in comment, skipping over double '\' characters.
*/
private void scanCommentChar() {
scanChar();
if (ch == '\\') {
bp++;
} else {
}
}
}
/** Append a character to sbuf.
*/
}
}
/** Read next character in character or string literal and copy into sbuf.
*/
private void scanLitChar() {
if (ch == '\\') {
bp++;
putChar('\\');
scanChar();
} else {
scanChar();
switch (ch) {
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
scanChar();
scanChar();
scanChar();
}
}
break;
case 'b':
case 't':
case 'n':
case 'f':
case 'r':
case '\'':
case '\"':
case '\\':
default:
}
}
}
}
char saveCh;
int savePos;
do {
if (ch != '_') {
} else {
if (!allowUnderscoresInLiterals) {
allowUnderscoresInLiterals = true;
}
}
scanChar();
if (saveCh == '_')
}
/** Read fractional part of hexadecimal floating point number.
*/
private void scanHexExponentAndSuffix() {
scanChar();
scanChar();
}
scanDigits(10);
if (!allowHexFloats) {
allowHexFloats = true;
}
else if (!hexFloatsWork)
lexError("unsupported.cross.fp.lit");
} else
lexError("malformed.fp.lit");
} else {
lexError("malformed.fp.lit");
}
scanChar();
} else {
scanChar();
}
}
}
/** Read fractional part of floating point number.
*/
private void scanFraction() {
scanDigits(10);
}
scanChar();
scanChar();
}
scanDigits(10);
return;
}
lexError("malformed.fp.lit");
}
}
/** Read fractional part and 'd' or 'f' suffix of floating point number.
*/
private void scanFractionAndSuffix() {
this.radix = 10;
scanFraction();
scanChar();
} else {
scanChar();
}
}
}
/** Read fractional part and 'd' or 'f' suffix of floating point number.
*/
this.radix = 16;
scanChar();
seendigit = true;
scanDigits(16);
}
if (!seendigit)
lexError("invalid.hex.number");
else
}
private void skipIllegalUnderscores() {
if (ch == '_') {
while (ch == '_')
scanChar();
}
}
/** Read a number.
* @param radix The radix of the number; one of 2, j8, 10, 16.
*/
// for octal, allow base-10 digit in case it's a float literal
boolean seendigit = false;
seendigit = true;
}
scanChar();
} else if (digitRadix == 10 &&
} else {
scanChar();
token = LONGLITERAL;
} else {
token = INTLITERAL;
}
}
}
/** Read an identifier.
*/
private void scanIdent() {
boolean isJavaIdentifierPart;
char high;
do {
// optimization, was: putChar(ch);
scanChar();
switch (ch) {
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
case '$': case '_':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '\u0000': case '\u0001': case '\u0002': case '\u0003':
case '\u0004': case '\u0005': case '\u0006': case '\u0007':
case '\u0008': case '\u000E': case '\u000F': case '\u0010':
case '\u0011': case '\u0012': case '\u0013': case '\u0014':
case '\u0015': case '\u0016': case '\u0017':
case '\u0018': case '\u0019': case '\u001B':
case '\u007F':
break;
case '\u001A': // EOI is also a legal identifier part
return;
}
break;
default:
if (ch < '\u0080') {
// all ASCII range chars already handled, above
isJavaIdentifierPart = false;
} else {
high = scanSurrogates();
if (high != 0) {
} else {
}
} else {
}
}
if (!isJavaIdentifierPart) {
return;
}
}
} while (true);
}
/** Are surrogates supported?
*/
private static boolean surrogatesSupported() {
try {
return true;
} catch (NoSuchMethodError ex) {
return false;
}
}
/** Scan surrogate pairs. If 'ch' is a high surrogate and
* the next character is a low surrogate, then put the low
* surrogate in 'ch', and return the high surrogate.
* otherwise, just return 0.
*/
private char scanSurrogates() {
scanChar();
return high;
}
}
return 0;
}
/** Return true if ch can be part of an operator.
*/
switch (ch) {
case '!': case '%': case '&': case '*': case '?':
case '+': case '-': case ':': case '<': case '=':
case '>': case '^': case '|': case '~':
case '@':
return true;
default:
return false;
}
}
/** Read longest possible sequence of special characters and convert
* to token.
*/
private void scanOperator() {
while (true) {
sp--;
break;
}
scanChar();
}
}
/**
* Scan a documention comment; determine if a deprecated tag is present.
* Called once the initial /, * have been skipped, positioned at the second *
* (which is treated as the beginning of the first line).
* Stops positioned at the closing '/'.
*/
@SuppressWarnings("fallthrough")
private void scanDocComment() {
boolean deprecatedPrefix = false;
// Skip optional WhiteSpace at beginning of line
}
// Skip optional consecutive Stars
if (ch == '/') {
return;
}
}
// Skip optional WhiteSpace after Stars
}
deprecatedPrefix = false;
// At beginning of line in the JavaDoc sense.
deprecatedPrefix = true;
}}}}}}}}}}}
deprecatedFlag = true;
} else if (ch == '*') {
if (ch == '/') {
deprecatedFlag = true;
return;
}
}
}
// Skip rest of line
switch (ch) {
case '*':
if (ch == '/') {
return;
}
break;
case CR: // (Spec 3.4)
continue forEachLine;
}
/* fall through to LF case */
case LF: // (Spec 3.4)
continue forEachLine;
default:
}
} // rest of line
} // forEachLine
return;
}
/** The value of a literal token, recorded as a string.
* For integers, leading 0x and 'l' suffixes are suppressed.
*/
}
/** Read token.
*/
public void nextToken() {
try {
prevEndPos = endPos;
sp = 0;
while (true) {
switch (ch) {
case ' ': // (Spec 3.6)
case '\t': // (Spec 3.6)
case FF: // (Spec 3.6)
do {
scanChar();
break;
case LF: // (Spec 3.4)
scanChar();
break;
case CR: // (Spec 3.4)
scanChar();
scanChar();
}
break;
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
case '$': case '_':
scanIdent();
return;
case '0':
scanChar();
scanChar();
if (ch == '.') {
scanHexFractionAndSuffix(false);
lexError("invalid.hex.number");
} else {
scanNumber(16);
}
if (!allowBinaryLiterals) {
allowBinaryLiterals = true;
}
scanChar();
lexError("invalid.binary.number");
} else {
scanNumber(2);
}
} else {
putChar('0');
if (ch == '_') {
do {
scanChar();
} while (ch == '_');
}
}
scanNumber(8);
}
return;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
scanNumber(10);
return;
case '.':
scanChar();
putChar('.');
} else if (ch == '.') {
scanChar();
if (ch == '.') {
scanChar();
putChar('.');
} else {
lexError("malformed.fp.lit");
}
} else {
}
return;
case ',':
case ';':
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case '/':
scanChar();
if (ch == '/') {
do {
}
break;
} else if (ch == '*') {
scanChar();
if (ch == '*') {
} else {
if (ch == '*') {
scanChar();
if (ch == '/') break;
} else {
}
}
}
if (ch == '/') {
scanChar();
break;
} else {
lexError("unclosed.comment");
return;
}
} else if (ch == '=') {
scanChar();
} else {
}
return;
case '\'':
scanChar();
if (ch == '\'') {
lexError("empty.char.lit");
} else {
scanLitChar();
if (ch == '\'') {
scanChar();
token = CHARLITERAL;
} else {
}
}
return;
case '\"':
scanChar();
scanLitChar();
if (ch == '\"') {
scanChar();
} else {
}
return;
default:
scanOperator();
} else {
boolean isJavaIdentifierStart;
if (ch < '\u0080') {
// all ASCII range chars already handled, above
isJavaIdentifierStart = false;
} else {
char high = scanSurrogates();
if (high != 0) {
} else {
}
} else {
}
}
if (isJavaIdentifierStart) {
scanIdent();
} else {
scanChar();
}
}
return;
}
}
} finally {
if (scannerDebug)
+ "|");
}
}
/** Return the current token, set by nextToken().
*/
return token;
}
/** Sets the current token.
* This method is primarily used to update the token stream when the
* parser is handling the end of nested type arguments such as
* {@code List<List<String>>} and needs to disambiguate between
* repeated use of ">" and relation operators such as ">>" and ">>>". Noting
* that this does not handle arbitrary tokens containing Unicode escape
* sequences.
*/
prevEndPos = pos;
}
/** Return the current token's position: a 0-based
* offset from beginning of the raw input stream
* (before unicode translation)
*/
public int pos() {
return pos;
}
/** Return the last character position of the current token.
*/
public int endPos() {
return endPos;
}
/** Return the last character position of the previous token.
*/
public int prevEndPos() {
return prevEndPos;
}
/** Return the position where a lexical error occurred;
*/
public int errPos() {
return errPos;
}
/** Set the position where a lexical error occurred;
*/
}
/** Return the name of an identifier or token for the current token.
*/
return name;
}
/** Return the radix of a numeric literal token.
*/
public int radix() {
return radix;
}
/** Has a @deprecated been encountered in last doc comment?
* This needs to be reset by client with resetDeprecatedFlag.
*/
public boolean deprecatedFlag() {
return deprecatedFlag;
}
public void resetDeprecatedFlag() {
deprecatedFlag = false;
}
/**
* Returns the documentation string of the current token.
*/
return null;
}
/**
* Returns a copy of the input buffer, up to its inputLength.
* Unicode escape sequences are not translated.
*/
public char[] getRawCharacters() {
return chars;
}
/**
* Returns a copy of a character array subset of the input buffer.
* The returned array begins at the <code>beginIndex</code> and
* extends to the character at index <code>endIndex - 1</code>.
* Thus the length of the substring is <code>endIndex-beginIndex</code>.
* This behavior is like
* <code>String.substring(beginIndex, endIndex)</code>.
* Unicode escape sequences are not translated.
*
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @throws IndexOutOfBounds if either offset is outside of the
* array bounds
*/
return chars;
}
public enum CommentStyle {
LINE,
}
/**
* Called when a complete comment has been scanned. pos and endPos
* will mark the comment boundary.
*/
if (scannerDebug)
+ "|");
}
/**
* Called when a complete whitespace run has been scanned. pos and endPos
* will mark the whitespace boundary.
*/
protected void processWhiteSpace() {
if (scannerDebug)
+ "|");
}
/**
* Called when a line terminator has been processed.
*/
protected void processLineTerminator() {
if (scannerDebug)
+ "|");
}
/** Build a map for translating between line numbers and
* positions in the input.
*
* @return a LineMap */
}
}