-
Notifications
You must be signed in to change notification settings - Fork 0
/
PL0.java
188 lines (168 loc) · 4.34 KB
/
PL0.java
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
import java.io.*;
/**
*<p>这个版本的 PL/0 编译器根据 C 语言的版本改写而成。两个版本在基本逻辑上是一致
*的,有些地方可能有所改动,例如getsym()和statement()两个函数,另外请注意C语言
*版本中的全局变量分散到构成编译器各个类中,为便于查找,保留了这些全局变量原来的名字。</p>
*
*<p>阅读过程中若有疑问请及时咨询你的助教。</p>
*/
public class PL0 {
// 编译程序的常数
/**
* 符号的最大长度
*/
public static final int al = 10;
/**
* 最大允许的数值
*/
public static final int amax = (int)((1 << 10) - 1);
/**
* 最多的虚拟机代码数
*/
public static final int cxmax = 500;
/**
* 最大允许过程嵌套声明层数 [0, levmax]
*/
public static final int levmax = 3;
/**
* number的最大位数
*/
public static final int nmax = 14;
/**
* 关键字个数
*/
public static final int norw = 32;
/**
* 名字表容量
*/
public static final int txmax = 100;
// 一些全局变量,其他关键的变量分布如下:
// cx, code : Interpreter
// dx : Parser
// tx, table : Table
/**
* 输出虚拟机代码
*/
public static PrintStream fa;
/**
* 输出源文件及其各行对应的首地址
*/
public static PrintStream fa1;
/**
* 输出结果
*/
public static PrintStream fa2;
/**
* 输出名字表
*/
public static PrintStream fas;
/**
* 显示虚拟机代码与否
*/
public static boolean listswitch;
/**
* 显示名字表与否
*/
public static boolean tableswitch;
// 一个典型的编译器的组成部分
/**
* 词法分析器
*/
public static Scanner lex;
/**
* 语法分析器
*/
public static Parser parser;
/**
* 类P-Code解释器(及目标代码生成工具)
*/
public static Interpreter interp;
/**
* 名字表
*/
public static Table table;
// 为避免多次创建BufferedReader,我们使用全局统一的Reader
/**
* 标准输入
*/
public static BufferedReader stdin;
/**
* 构造函数,初始化编译器所有组成部分
* @param fin PL/0 源文件的输入流
*/
public PL0(BufferedReader fin) {
// 各部件的构造函数中都含有C语言版本的 init() 函数的一部分代码
lex = new Scanner(fin);
interp = new Interpreter();
table = new Table();
parser = new Parser(lex, table, interp);
}
/**
* 执行编译动作
* @return 是否编译成功
*/
boolean compile() {
boolean abort = false;
try {
PL0.fa = new PrintStream("fa.tmp");
PL0.fas = new PrintStream("fas.tmp");
parser.start(); // 开始语法分析过程(连同语法检查、目标代码生成)
} catch (Error e) {
// 如果是发生严重错误则直接中止
abort = true;
} catch (IOException e) {
} finally {
PL0.fa.close();
PL0.fa1.close();
PL0.fas.close();
}
if (abort)
System.exit(0);
// 编译成功是指完成编译过程并且没有错误
return (Err.err == 0);
}
/**
* 主函数
*/
public static void main(String[] args) {
// 原来 C 语言版的一些语句划分到compile()和Parser.parse()中
String fname = "";
stdin = new BufferedReader(new InputStreamReader(System.in));
BufferedReader fin;
try {
// 输入文件名
fname = "";
System.out.print("Input pl/0 file? ");
while (fname.equals(""))
fname = stdin.readLine();
fin = new BufferedReader(new FileReader(fname), 4096);
// 是否输出虚拟机代码
fname = "";
System.out.print("List object code?(Y/N)");
while (fname.equals(""))
fname = stdin.readLine();
PL0.listswitch = (fname.charAt(0)=='y' || fname.charAt(0)=='Y');
// 是否输出名字表
fname = "";
System.out.print("List symbol table?(Y/N)");
while (fname.equals(""))
fname = stdin.readLine();
PL0.tableswitch = (fname.charAt(0)=='y' || fname.charAt(0)=='Y');
PL0.fa1 = new PrintStream("fa1.tmp");
PL0.fa1.println("Input pl/0 file? " + fname);
// 构造编译器并初始化
PL0 pl0 = new PL0(fin);
if (pl0.compile()) {
// 如果成功编译则接着解释运行
PL0.fa2 = new PrintStream("fa2.tmp");
interp.interpret();
PL0.fa2.close();
} else {
System.out.print("Errors in pl/0 program");
}
} catch (IOException e) {
System.out.println("Can't open file!");
}
System.out.println();
}
}