-
Notifications
You must be signed in to change notification settings - Fork 393
/
PlayScript.java
398 lines (334 loc) · 13.5 KB
/
PlayScript.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
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
package play;
import java.io.*;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* 命令行工具。可以执行一个脚本,或者以REPL模式运行。
*/
public class PlayScript {
public static void main(String args[]) {
//String script = "45+10*2;";
//String script = "int age = 44; { int i = 10; age+i;}";
//String script = "int age = 44; for(int i = 0;i<10;i++) { age = age + 2;} int i = 8;";
//String script = "int b= 10; int myfunc(int a) {return a+b+3;} myfunc(2);";
//String script = "class myclass{int a=2; int b; myclass(){ b = 3;} } myclass c = myclass(); c.b;";
//String script = "class class1{int a=2; int b; void method1(){println(\"in class1\");}} class class2 extends class1{int b = 5; void method1(){println(\"in class2\");} } class1 c = class2(); println(c.a); println(c.b); c.method1();";
//String script = "class myclass{int a; int b; myclass(){a=1; b=2;} int calc(){return a + b;} } myclass c = myclass(); c.calc();";
//String script = "println(2);";
//String script = "int fun1(int a){return a+1;} println(fun1(2)); function int(int) fun2=fun1; fun2(3);";
//String script = "int a=0; function int() fun1(){int b=0; int inner(){a=a+1; b=b+1; return b;} return inner;} function int() fun2 = fun1(); println(fun2()); println(fun2());";
//String script = "println(2+3.5); println(\"Hello \" + 45); ";
//test asm generation
//String script = null; //"int a = 1; int b =2; int c; c=a+b;";
//String script = "int fun1(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8){int c = 10; return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + c;} println(\"fun1: %d\", fun1(1,2,3,4,5,6,7,8));".replaceAll("\\\\", "");
//脚本
String script = null;
Map params = null;
//解析参数
try{
params = parseParams(args);
}catch (Exception e){
System.out.println(e.getMessage());
return;
}
boolean help = params.containsKey("help") ? (Boolean) params.get("help") : false;
if (help){
showHelp();
return;
}
//从源代码读取脚本
String scriptFile = params.containsKey("scriptFile") ? (String)params.get("scriptFile") : null;
if (scriptFile != null) {
try {
script = readTextFile(scriptFile);
} catch (IOException e) {
System.out.println("unable to read from : " + scriptFile);
return;
}
}
//是否生成汇编代码
boolean genAsm = params.containsKey("genAsm") ? (Boolean) params.get("genAsm") : false;
//是否生成字节码
boolean genByteCode = params.containsKey("genByteCode") ? (Boolean) params.get("genByteCode") : false;
//打印编译过程中的信息
boolean verbose = params.containsKey("verbose") ? (Boolean) params.get("verbose") : false;
//打印AST
boolean ast_dump = params.containsKey("ast_dump") ? (Boolean) params.get("ast_dump") : false;
//进入REPL
if (script == null) {
REPL(verbose, ast_dump);
}
//生成汇编代码
else if (genAsm) {
//输出文件
String outputFile = params.containsKey("outputFile") ? (String)params.get("outputFile") : null;
generateAsm(script, outputFile);
}
//生成Java字节码
else if (genByteCode) {
//输出文件
//String outputFile = params.containsKey("outputFile") ? (String)params.get("outputFile") : null;
byte[] bc = generateByteCode(script);
runJavaClass("DefaultPlayClass", bc);
}
//执行脚本
else {
PlayScriptCompiler compiler = new PlayScriptCompiler();
AnnotatedTree at = compiler.compile(script, verbose, ast_dump);
if (!at.hasCompilationError()) {
Object result = compiler.Execute(at);
//System.out.println(result);
}
}
}
/**
* 解析参数
* @param args
* @return
*/
private static Map parseParams(String args[]) throws Exception {
Map<String,Object> params = new HashMap<>();
for (int i = 0; i < args.length; i++) {
//输出汇编代码
if (args[i].equals("-S")) {
params.put("genAsm",true);
}
//生成字节码
else if (args[i].equals("-bc")){
params.put("genByteCode",true);
}
//显示作用域和符号
else if (args[i].equals("-h") || args[i].equals("--help")){
params.put("help",true);
}
//显示作用域和符号
else if (args[i].equals("-v")){
params.put("verbose",true);
}
//显示作用域和符号
else if (args[i].equals("-ast-dump")){
params.put("ast_dump",true);
}
//输出文件
else if (args[i].equals("-o")) {
if (i + 1 < args.length) {
//outputFile = args[++i]; //让i的序号增加一个
params.put("outputFile", args[++i]);
} else {
//System.out.println("Expecting a filename after -o");
throw new Exception("Expecting a filename after -o");
}
}
//不认识的参数
else if (args[i].startsWith("-")){
throw new Exception("Unknow parameter : " + args[i]);
}
//脚本文件
else {
params.put("scriptFile", args[i]);
//scriptFile = args[i];
}
}
return params;
}
/**
* 打印帮助信息
*/
private static void showHelp(){
System.out.println("usage: java play.PlayScript [-h | --help | -o outputfile | -S | -bc | -v | -ast-dump] [scriptfile]");
System.out.println("\t-h or --help : print this help information");
System.out.println("\t-v verbose mode : dump AST and symbols");
System.out.println("\t-ast-dump : dump AST in lisp style");
System.out.println("\t-o outputfile : file pathname used to save generated code, eg. assembly code");
System.out.println("\t-S : compile to assembly code");
System.out.println("\t-bc : compile to java byte code");
System.out.println("\tscriptfile : file contains playscript code");
System.out.println("\nexamples:");
System.out.println("\tjava play.PlayScript");
System.out.println("\t>>interactive REPL mode");
System.out.println();
System.out.println("\tjava play.PlayScript -v");
System.out.println("\t>>enter REPL with verbose mode, dump ast and symbols");
System.out.println();
System.out.println("\tjava play.PlayScript scratch.play");
System.out.println("\t>>compile and execute scratch.play");
System.out.println();
System.out.println("\tjava play.PlayScript -v scratch.play");
System.out.println("\t>>compile and execute scratch.play in verbose mode, dump ast and symbols");
System.out.println();
System.out.println("\tjava play.PlayScript -bc scratch.play");
System.out.println("\t>>compile to bytecode, save as DefaultPlayClass.class and run it");
System.out.println();
}
/**
* 生成ASM
*
* @param script 脚本
* @param outputFile 输出的文件名
*/
private static void generateAsm(String script, String outputFile) {
PlayScriptCompiler compiler = new PlayScriptCompiler();
AnnotatedTree at = compiler.compile(script);
AsmGen asmGen = new AsmGen(at);
String asm = asmGen.generate();
if (outputFile != null) {
try {
writeTextFile(outputFile, asm);
} catch (IOException e) {
System.out.println("unable to write to : " + outputFile);
return;
}
} else {
System.out.println(asm);
}
}
/**
* 生成字节码,保存到DefaultPlayClass.class
*
* @param script 脚本
*/
private static byte[] generateByteCode(String script) {
PlayScriptCompiler compiler = new PlayScriptCompiler();
AnnotatedTree at = compiler.compile(script);
ByteCodeGen bcGen = new ByteCodeGen(at);
byte[] bc = bcGen.generate();
String outputFile = "DefaultPlayClass.class";
try {
File file = new File(outputFile);
FileOutputStream fos = new FileOutputStream(file);
fos.write(bc);
fos.close();
} catch (IOException e) {
System.out.println("unable to write to : " + outputFile);
}
return bc;
}
/**
* 读文本文件
* @param pathName
* @return
* @throws IOException
*/
private static String readTextFile(String pathName) throws IOException {
StringBuffer buffer = new StringBuffer();
try (FileReader reader = new FileReader(pathName);
BufferedReader br = new BufferedReader(reader)) {
String line;
while ((line = br.readLine()) != null) {
buffer.append(line).append('\n');
}
}
return buffer.toString();
}
/**
* 写文本文件
* @param pathName
* @param text
* @throws IOException
*/
public static void writeTextFile(String pathName, String text) throws IOException {
File file = new File(pathName);
file.createNewFile();
try (FileWriter writer = new FileWriter(file);
BufferedWriter out = new BufferedWriter(writer)) {
StringReader reader = new StringReader(text);
BufferedReader br = new BufferedReader(reader);
String line;
while ((line = br.readLine()) != null) {
out.write(line);
out.newLine();
}
out.flush(); // 把缓存区内容压入文件
}
}
/**
* REPL
*/
private static void REPL(boolean verbose, boolean ast_dump) {
System.out.println("Enjoy PlayScript!");
PlayScriptCompiler compiler = new PlayScriptCompiler();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String script = "";
String scriptLet = "";
System.out.print("\n>"); //提示符
while (true) {
try {
String line = reader.readLine().trim();
if (line.equals("exit();")) {
System.out.println("good bye!");
break;
}
scriptLet += line + "\n";
if (line.endsWith(";")) {
// 解析整个脚本文件
AnnotatedTree at = compiler.compile(script + scriptLet, verbose, ast_dump);
//重新执行整个脚本
if (!at.hasCompilationError()) {
Object result = compiler.Execute(at);
System.out.println(result);
script = script + scriptLet;
}
System.out.print("\n>"); //提示符
scriptLet = "";
}
} catch (Exception e) {
// e.printStackTrace();
System.out.println(e.getLocalizedMessage());
System.out.print("\n>"); //提示符
scriptLet = "";
}
}
}
/**
* 批量运行所有的示例程序,每个示例程序执行完毕以后,需要按一个键,再继续执行下一个程序。
*/
private static void batchTest() {
}
/**
* 运行指定名称的Java类
* @param className
*/
private static void runJavaClass(String className, byte[] b){
try {
//java.lang.Class clazz = java.lang.Class.forName(className);
java.lang.Class clazz = loadClass(className,b);
Method method = clazz.getMethod("main", String[].class);
method.invoke(null, (Object)new String[]{});
}
catch (Exception e){
e.printStackTrace();
}
}
/**
* 从byte数组加载类
* @param className
* @param b
* @return
*/
private static java.lang.Class loadClass(String className, byte[] b) {
// Override defineClass (as it is protected) and define the class.
java.lang.Class clazz = null;
try {
ClassLoader loader = ClassLoader.getSystemClassLoader();
java.lang.Class cls = java.lang.Class.forName("java.lang.ClassLoader");
java.lang.reflect.Method method =
cls.getDeclaredMethod(
"defineClass",
new java.lang.Class[] { String.class, byte[].class, int.class, int.class });
// Protected method invocation.
method.setAccessible(true);
try {
Object[] args =
new Object[] { className, b, new Integer(0), new Integer(b.length)};
clazz = (java.lang.Class) method.invoke(loader, args);
} finally {
method.setAccessible(false);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
return clazz;
}
}