📄 scanner.java
字号:
/** * The scanner transforms the input file into a stream of tokens. The
* "lookahead" may be used to exam the token following the current token. This
* is sometimes required when the current token does not reveal the following
* construct (e.g. variable definitions and method definition both start with an
* identifier). The scanner has to be advanced to the next token explicitly by
* calling advance().
*
* @see Token */
public class Scanner {
private LexemReader lexemReader;
private Token currentToken;
private Token lookAheadToken;
/**
* Creates an instance of the scanner and tokenizes the input file.
*
* @param fileName
* name of the input file
* @throws ScannerException
* If an I/O exception occured
*/
Scanner(String fileName) throws ScannerException {
lexemReader = new LexemReader(fileName);
advance(); // read first token into currentToken
}
/**
* Returns the current token without advancing to the next.
*
* @see Token
*/
Token token() {
return currentToken;
}
/**
* Returns the following token (again without advancing).
*
* @see Token
* @throws ScannerException
* I/O error or illegal character.
*/
Token followingToken() throws ScannerException {
// if lookahead has been done before, don't read another token
if (lookAheadToken == null)
lookAheadToken = scanToken();
return lookAheadToken;
}
/**
* Advances the scanner to the next token.
*
* @throws ScannerException
* I/O error or illegal character.
*/
void advance() throws ScannerException {
if (lookAheadToken != null) {
currentToken = lookAheadToken;
lookAheadToken = null; // erase lookahead cache; causing real read
// next time and re-enable lookahead-read
} else
currentToken = scanToken();
}
private Token scanToken() throws ScannerException {
int ch = lexemReader.nextNonWhiteCharacter();
// return EOF token if no more characters are availabe
if (ch == -1)
return new SimpleToken(lexemReader.line(), lexemReader.pos(), '~');
// continue with a character rather than an integer value
char c = (char) ch;
switch (c) {
case '.':
case ',':
case ';':
return new SimpleToken(lexemReader.line(), lexemReader.pos(), c);
case '(':
case ')':
case '{':
case '}':
return new BracketToken(lexemReader.line(), lexemReader.pos(), c);
case '/':
if (lexemReader.followingCharacter() == '/')
return consumeComment();
else
return new OperatorToken(lexemReader.line(), lexemReader.pos(),
c);
case '+':
case '-':
case '*':
case '!':
case '>':
case '<':
return new OperatorToken(lexemReader.line(), lexemReader.pos(), c);
case '&':
case '|':
if (lexemReader.followingCharacter() == c)//is it one of "&&",
// "||"?
{
lexemReader.nextCharacter();
return new OperatorToken(lexemReader.line(), lexemReader.pos(),
c);
} else
throw new ScannerException(lexemReader.line(), lexemReader
.pos(), "Unknown Operator");
case '=':
if (lexemReader.followingCharacter() == c)//is it "=="?
{
lexemReader.nextCharacter();
return new OperatorToken(lexemReader.line(), lexemReader.pos(),
c);
} else
return new SimpleToken(lexemReader.line(), lexemReader.pos(), c); // found
// assignment
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return composeNumberLiteral(c, lexemReader.line(), lexemReader
.pos());
default:
return composeWord(c, lexemReader.line(), lexemReader.pos());
}
}
private Token consumeComment() throws ScannerException {
while (lexemReader.nextCharacter() != '\n')
;
return scanToken();
}
private Token composeNumberLiteral(char c, int line, int pos)
throws ScannerException {
int val = c - '0';
while (isDigit(lexemReader.followingCharacter())) {
c = (char) lexemReader.nextCharacter();
val *= 10;
val += c - '0';
}
return new NumberLiteralToken(line, pos, val);
}
private boolean isDigit(char c) {
return c >= '0' && c <= '9';
}
private Token composeWord(char c, int line, int pos)
throws ScannerException {
StringBuffer charSequence = new StringBuffer(99);
charSequence.append(c);
while (isAlphaNumeric(lexemReader.followingCharacter())) {
c = (char) lexemReader.nextCharacter();
charSequence.append(c);
}
String word = charSequence.toString();
if (isBooleanLiteral(word))
return new BooleanLiteralToken(line, pos, word.equals("true"));
if (isKeyword(word))
return new KeywordToken(line, pos, word);
return new IdentifierToken(line, pos, word);
}
private boolean isAlphaNumeric(char c) {
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
|| isDigit(c);
}
private boolean isKeyword(String s) {
String[] keywords = { "while", "if", "else", "return", "new",
"void", "boolean", "int", "direction", "Robot" };
return contains(keywords, s);
}
private boolean isBooleanLiteral(String s) {
String[] booleanLiterals = { "true", "false" };
return contains(booleanLiterals, s);
}
private boolean contains(String[] a, String s) {
for (int i = 0; i < a.length; i++)
if (s.equals(a[i]))
return true;
return false;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -