?? scanner.java
字號:
import java.io.BufferedReader;
import java.io.IOException;
/**
* 詞法分析器負責的工作是從源代碼里面讀取文法符號,這是PL/0編譯器的主要組成部分之一。
*/
public class Scanner {
/**
* 剛剛讀入的字符
*/
private char ch = ' ';
public int isArray =0;
/**
* 當前讀入的行
*/
private char[] line;
/**
* 當前行的長度(line length)
*/
public int ll = 0;
/**
* 當前字符在當前行中的位置(character counter)
*/
public int cc = 0;
/**
* 當前讀入的符號
*/
public Symbol sym;
/**
* 保留字列表(注意保留字的存放順序)
*/
private String[] word;
/**
* 保留字對應的符號值
*/
private Symbol[] wsym;
/**
* 單字符的符號值
*/
private Symbol[] ssym;
// 輸入流
private BufferedReader in;
/**
* 標識符名字(如果當前符號是標識符的話)
* @see Parser
* @see Table#enter
*/
public String id;
/**
* 數值大小(如果當前符號是數字的話)
* @see Parser
* @see Table#enter
*/
public int num;
/**
* 初始化詞法分析器
* @param input PL/0 源文件輸入流
*/
public Scanner(BufferedReader input) {
in = input;
// 設置單字符符號
ssym = new Symbol[256];
java.util.Arrays.fill(ssym, Symbol.nul);
ssym['+'] = Symbol.plus;
ssym['-'] = Symbol.minus;
ssym['*'] = Symbol.times;
ssym['/'] = Symbol.slash;
ssym['('] = Symbol.lparen;
ssym[')'] = Symbol.rparen;
ssym['='] = Symbol.eql;
ssym[','] = Symbol.comma;
ssym['.'] = Symbol.period;
ssym['#'] = Symbol.neq;
ssym[';'] = Symbol.semicolon;
// 設置保留字名字,按照字母順序,便于折半查找
word = new String[] {"begin", "call", "const", "do", "else","end", "if",
"odd", "procedure", "read", "then", "var", "while", "write"};
// 設置保留字符號
wsym = new Symbol[PL0.norw];
wsym[0] = Symbol.beginsym;
wsym[1] = Symbol.callsym;
wsym[2] = Symbol.constsym;
wsym[3] = Symbol.dosym;
wsym[4] = Symbol.elsesym;
wsym[5] = Symbol.endsym;
wsym[6] = Symbol.ifsym;
wsym[7] = Symbol.oddsym;
wsym[8] = Symbol.procsym;
wsym[9] = Symbol.readsym;
wsym[10] = Symbol.thensym;
wsym[11] = Symbol.varsym;
wsym[12] = Symbol.whilesym;
wsym[13] = Symbol.writesym;
}
/**
* 讀取一個字符,為減少磁盤I/O次數,每次讀取一行
*/
void getch() {
String l = "";
try {
if (cc == ll) {
while (l.equals(""))
l = in.readLine().toLowerCase() + "\n";
ll = l.length();
cc = 0;
line = l.toCharArray();
System.out.println(PL0.interp.cx + " " + l); //NN interp.cx
PL0.fa1.println(PL0.interp.cx + " " + l);
}
} catch (IOException e) {
throw new Error("program imcomplete");
}
ch = line[cc];
cc ++;
}
/**
* 詞法分析,獲取一個詞法符號,是詞法分析器的重點
*/
public void getsym() {
// Wirth 的 PL/0 編譯器使用一系列的if...else...來處理
// 但是你的助教認為下面的寫法能夠更加清楚地看出這個函數的處理邏輯
while (Character.isWhitespace(ch)) // 跳過所有空白字符
getch();
if (ch >= 'a' && ch <= 'z') {
// 關鍵字或者一般標識符
matchKeywordOrIdentifier();
} else if (ch >= '0' && ch <= '9') {
// 數字
matchNumber();
} else {
// 操作符
matchOperator();
}
}
/**
* 分析關鍵字或者一般標識符
*/
void matchKeywordOrIdentifier() {
int i;
StringBuilder sb = new StringBuilder(PL0.al); //NN StringBuilder
// 首先把整個單詞讀出來
do {
sb.append(ch);
getch();
} while (ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9');
id = sb.toString();
// 然后搜索是不是保留字(請注意使用的是什么搜索方法)
i = java.util.Arrays.binarySearch(word, id);
// 最后形成符號信息
if (i < 0) {
// 一般標識符
sym = Symbol.ident;
if (ch=='(')
isArray=1;
} else {
// 關鍵字
sym = wsym[i];
}
}
/**
* 分析數字
*/
void matchNumber() {
int k = 0;
sym = Symbol.number;
num = 0;
do {
num = 10*num + Character.digit(ch, 10);
k++;
getch();
} while (ch>='0' && ch<='9'); // 獲取數字的值
k--;
if (k > PL0.nmax)
Err.report(30);
}
/**
* 分析操作符
*/
void matchOperator() {
// 請注意這里的寫法跟Wirth的有點不同
switch (ch) {
case ':': // 賦值符號
getch();
if (ch == '=') {
sym = Symbol.becomes;
getch();
} else {
// 不能識別的符號
sym = Symbol.nul;
}
break;
case '<': // 小于或者小于等于
getch();
if (ch == '=') {
sym = Symbol.leq;
getch();
} else {
sym = Symbol.lss;
}
break;
case '>': // 大于或者大于等于
getch();
if (ch == '=') {
sym = Symbol.geq;
getch();
} else {
sym = Symbol.gtr;
}
break;
default: // 其他為單字符操作符(如果符號非法則返回nil)
sym = ssym[ch];
if (sym != Symbol.period)
getch();
break;
}
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -