forked from gdut-yy/PL0
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScanner.java
More file actions
236 lines (213 loc) · 4.85 KB
/
Copy pathScanner.java
File metadata and controls
236 lines (213 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
package net.devyy;
import java.io.BufferedReader;
import java.io.IOException;
/**
* 词法分析器负责的工作是从源代码里面读取文法符号,这是PL/0编译器的主要组成部分之一。
*/
public class Scanner {
/**
* 刚刚读入的字符
*/
private char ch = ' ';
/**
* 当前读入的行
*/
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", "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.endsym;
wsym[5] = Symbol.ifsym;
wsym[6] = Symbol.oddsym;
wsym[7] = Symbol.procsym;
wsym[8] = Symbol.readsym;
wsym[9] = Symbol.thensym;
wsym[10] = Symbol.varsym;
wsym[11] = Symbol.whilesym;
wsym[12] = 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);
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);
// 首先把整个单词读出来
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;
} 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;
}
}
}