├── .classpath
├── .gitignore
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── README.md
├── compile document.docx
├── src
├── AllPcode.java
├── AllSymbol.java
├── GSAnalysis.java
├── Interpreter.java
├── LexAnalysis.java
├── MyCompiler.java
├── Operator.java
├── PerPcode.java
├── PerSymbol.java
├── SymType.java
└── Token.java
└── testPL0
├── demo1.txt
├── demo2.txt
├── demo3.txt
├── demo4.txt
└── demo5.txt
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | MyCompiler
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.8
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.8
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 本学期修了《编译原理》这门课。课程大作业是实现一个PL/0编译器。接下来将记录在实现过程中的心得、遇到的问题和解决办法,如有错误之处,欢迎指正。
2 |
3 | ### PL/0语言描述
4 |
5 | PL/0型语言是Pascal语言的一个子集。作为一门教学用程序设计语言,它比PASCAL语言简单,并作了一些限制。PL0的程序结构比较完全,相应的选择,不但有常量,变量及过程声明,而且分支和循环结构也是一应俱全。
6 |
7 | PL/0文法的EBNF表示如下:
8 |
9 | ```
10 | <程序> ::= <分程序>.
11 | <分程序> ::= [<常量说明部分>][变量说明部分>][<过程说明部分>]<语句>
12 | <常量说明部分> ::= const<常量定义>{,<常量定义>};
13 | <常量定义> ::= <标识符>=<无符号整数>
14 | <无符号整数> ::= <数字>{<数字>}
15 | <标识符> ::= <字母>{<字母>|<数字>}
16 | <变量说明部分>::= var<标识符>{,<标识符>};
17 | <过程说明部分> ::= <过程首部><分程序>;{<过程说明部分>}
18 | <过程首部> ::= procedure<标识符>;
19 | <语句> ::= <赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句>|<重复语句>|<空>
20 | <赋值语句> ::= <标识符>:=<表达式>
21 | <表达式> ::= [+|-]<项>{<加法运算符><项>}
22 | <项> ::= <因子>{<乘法运算符><因子>}
23 | <因子> ::= <标识符>|<无符号整数>|'('<表达式>')‘
24 | <加法运算符> ::= +|-
25 | <乘法运算符> ::= *|/
26 | <条件> ::= <表达式><关系运算符><表达式>|odd<表达式>
27 | <关系运算符> ::= =|<>|<|<=|>|>=
28 | <条件语句> ::= if<条件>then<语句>[else<语句>]
29 | <当型循环语句> ::= while<条件>do<语句>
30 | <过程调用语句> ::= call<标识符>
31 | <复合语句> ::= begin<语句>{;<语句>}end
32 | <重复语句> ::= repeat<语句>{;<语句>}until<条件>
33 | <读语句> ::= read'('<标识符>{,<标识符>}')‘
34 | <写语句> ::= write'('<标识符>{,<标识符>}')‘
35 | <字母> ::= a|b|...|X|Y|Z
36 | <数字> ::= 0|1|2|...|8|9
37 | ```
38 |
39 | ### 实现效果
40 |
41 |
42 | 
43 |
44 |
45 | 项目整个界面分为导航栏,代码区,token表区,符号表区,Pcode区以及控制台。各分区的功能如下:
46 |
47 | | 分区 | 功能 |
48 | | :--------: | :----------: |
49 | | 导航栏 | 打开,关闭或保存文件;编译和执行代码 |
50 | | 代码区 | 展示并编辑代码 |
51 | | Token表区 | 展示代码中的token |
52 | | Symbol表区 | 展示代码编译过程中生成的symbol表 |
53 | | Pcode表区 | 展示代码生成的所有Pcode |
54 | | 控制台 | 输出编译信息 |
55 |
56 | 相关博客请前往[PL/0简单编译系统](http://www.jianshu.com/p/a6c93ca376d4)
57 |
--------------------------------------------------------------------------------
/compile document.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiyi001/PL0Compiler/d675c22a8dc0dbecca20419159ab3d63523d6a94/compile document.docx
--------------------------------------------------------------------------------
/src/AllPcode.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | /**
5 | * created by shiyi on 2016/12/14
6 | * 保存所有Pcode指令
7 | */
8 |
9 | public class AllPcode {
10 | List allPcode;
11 |
12 | /**
13 | * 代码的具体形式:
14 | * FLA
15 | * 其中:F段代表伪操作码
16 | * L段代表调用层与说明层的层差值
17 | * A段代表位移量(相对地址)
18 | * 进一步说明:
19 | * INT:为被调用的过程(包括主过程)在运行栈S中开辟数据区,这时A段为所需数据单元个数(包括三个连接数据);L段恒为0。
20 | * CAL:调用过程,这时A段为被调用过程的过程体(过程体之前一条指令)在目标程序区的入口地址。
21 | * LIT:将常量送到运行栈S的栈顶,这时A段为常量值。
22 | * LOD:将变量送到运行栈S的栈顶,这时A段为变量所在说明层中的相对位置。
23 | * STO:将运行栈S的栈顶内容送入某个变量单元中,A段为变量所在说明层中的相对位置。
24 | * JMP:无条件转移,这时A段为转向地址(目标程序)。
25 | * JPC:条件转移,当运行栈S的栈顶的布尔值为假(0)时,则转向A段所指目标程序地址;否则顺序执行。
26 | * OPR:关系或算术运算,A段指明具体运算,例如A=2代表算术运算“+”;A=12代表关系运算“>”等等。运算对象取自运行栈S的栈顶及次栈顶。
27 | *
28 | * OPR 0 0 过程调用结束后,返回调用点并退栈
29 | * OPR 0 1 栈顶元素取反
30 | * OPR 0 2 次栈顶与栈顶相加,退两个栈元素,结果值进栈
31 | * OPR 0 3 次栈顶减去栈顶,退两个栈元素,结果值进栈
32 | * OPR 0 4 次栈顶乘以栈顶,退两个栈元素,结果值进栈
33 | * OPR 0 5 次栈顶除以栈顶,退两个栈元素,结果值进栈
34 | * OPR 0 6 栈顶元素的奇偶判断,结果值在栈顶
35 | * OPR 0 7
36 | * OPR 0 8 次栈顶与栈顶是否相等,退两个栈元素,结果值进栈
37 | * OPR 0 9 次栈顶与栈顶是否不等,退两个栈元素,结果值进栈
38 | * OPR 0 10 次栈顶是否小于栈顶,退两个栈元素,结果值进栈
39 | * OPR 0 11 次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈
40 | * OPR 0 12 次栈顶是否大于栈顶,退两个栈元素,结果值进栈
41 | * OPR 0 13 次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈
42 | * OPR 0 14 栈顶值输出至屏幕
43 | * OPR 0 15 屏幕输出换行
44 | * OPR 0 16 从命令行读入一个输入置于栈顶
45 | */
46 |
47 | public AllPcode() {
48 | allPcode = new ArrayList();
49 | }
50 |
51 | public List getAllPcode() {
52 | return allPcode;
53 | }
54 |
55 | public int getPcodePtr() {
56 | return allPcode.size();
57 | }
58 |
59 | public void gen(PerPcode pcode) {
60 | allPcode.add(pcode);
61 | }
62 |
63 | public void gen(Operator L, int F, int A) {
64 | allPcode.add(new PerPcode(L, F, A));
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/AllSymbol.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | /**
5 | * created by shiyi on 2016/12/14
6 | * 符号表
7 | */
8 | public class AllSymbol {
9 | List allSymbol;
10 |
11 | private int con=1; //常量类型用1表示
12 | private int var=2; //变量类型用2表示
13 | private int proc=3; //过程类型用3表示
14 |
15 | private int ptr = 0;
16 |
17 | public AllSymbol() {
18 | allSymbol = new ArrayList();
19 | }
20 |
21 | //向符号表中插入常量
22 | public void enterConst(String name, int level, int value, int address) {
23 | allSymbol.add(new PerSymbol(con, value, level, address, 0, name));
24 | ptr++;
25 | }
26 |
27 | //向符号表中插入变量
28 | public void enterVar(String name, int level, int address) {
29 | allSymbol.add(new PerSymbol(var, level, address, 0, name));
30 | ptr++;
31 | }
32 |
33 | //向符号表中插入过程
34 | public void enterProc(String name, int level, int address) {
35 | allSymbol.add(new PerSymbol(proc, level, address, 0, name));
36 | ptr++;
37 | }
38 |
39 | //在符号表当前层查找变量是否存在
40 | //存疑?
41 | //这样暴力查找好像存在一些问题
42 | public boolean isNowExists(String name, int level) {
43 | for (int i = 0; i < allSymbol.size(); i++) {
44 | if (allSymbol.get(i).getName().equals(name) && allSymbol.get(i).getLevel() == level) {
45 | return true;
46 | }
47 | }
48 | return false;
49 | }
50 |
51 | //在符号表之前层查找符号是否存在
52 | //存疑?
53 | //暴力查找存在问题
54 | public boolean isPreExists(String name, int level) {
55 | for (int i = 0; i < allSymbol.size(); i++) {
56 | if (allSymbol.get(i).getName().equals(name) && allSymbol.get(i).getLevel() <= level) {
57 | return true;
58 | }
59 | }
60 | return false;
61 | }
62 |
63 | //按名称查找变量
64 | public PerSymbol getSymbol(String name) {
65 | for (int i = allSymbol.size() - 1; i >= 0; i--) {
66 | if (allSymbol.get(i).getName().equals(name)) {
67 | return allSymbol.get(i);
68 | }
69 | }
70 | return null;
71 | }
72 |
73 | //查找当前层所在的过程
74 | public int getLevelProc(int level) {
75 | for (int i = allSymbol.size() - 1; i >= 0; i--) {
76 | if (allSymbol.get(i).getType() == proc) {
77 | return i;
78 | }
79 | }
80 | return -1;
81 | }
82 |
83 | public List getAllSymbol() {
84 | return allSymbol;
85 | }
86 |
87 | public void setPtr(int _ptr) {
88 | ptr = _ptr;
89 | }
90 |
91 | public int getPtr() {
92 | return ptr;
93 | }
94 |
95 | public int getLength() {
96 | return allSymbol.size();
97 | }
98 |
99 | public int getCon() {
100 | return con;
101 | }
102 |
103 | public int getVar() {
104 | return var;
105 | }
106 |
107 | public int getProc() {
108 | return proc;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/GSAnalysis.java:
--------------------------------------------------------------------------------
1 | import java.io.File;
2 | import java.util.ArrayList;
3 | import java.util.List;
4 |
5 | public class GSAnalysis {
6 | private LexAnalysis lex;
7 | private List allToken; //保存词法分析结果
8 | private AllPcode allPcode; //保存生成的Pcode
9 | private AllSymbol allSymbol; //符号表管理
10 | private List errorMessage; //保存错误信息
11 |
12 | private boolean errorHappen = false; //记录编译过程中是否发生错误
13 | private int tokenPtr = 0; //指向当前token的指针
14 |
15 | private int level = 0;
16 | private int address = 0;
17 | private int addIncrement = 1;
18 |
19 | GSAnalysis(File file) {
20 | lex = new LexAnalysis(file);
21 | allToken = lex.getAllToken();
22 |
23 | allPcode = new AllPcode();
24 |
25 | allSymbol = new AllSymbol();
26 |
27 | errorMessage = new ArrayList();
28 | }
29 |
30 | public boolean compile() {
31 | program();
32 | return (!errorHappen);
33 | }
34 |
35 | private void program() {
36 | //<主程序>::=<分程序>.
37 | block();
38 | if (allToken.get(tokenPtr).getSt() == SymType.POI) {
39 | tokenPtr++;
40 | if (allToken.get(tokenPtr).getSt() != SymType.EOF) {
41 | errorHandle(18, "");
42 | }
43 | } else {
44 | errorHandle(17, "");
45 | }
46 | }
47 |
48 | private void block() {
49 | //<分程序>::=[<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>
50 | int address_cp = address; //保存之前的address值
51 |
52 | //初始化本层的相关变量
53 | int start = allSymbol.getPtr(); //本层变量声明的初始位置
54 | int pos = 0; //本层过程声明在符号表中的位置
55 | address = 3; //默认已3开始,前几位存放一些跳转关键变量,如原来的base(基地址),pc(程序计数器)等
56 | if (start > 0) {
57 | pos = allSymbol.getLevelProc(level);
58 | }
59 |
60 | //设置跳转指令,跳过声明部分,后面回填
61 | int tmpPcodePtr = allPcode.getPcodePtr();
62 | allPcode.gen(Operator.JMP, 0, 0);
63 |
64 | if (allToken.get(tokenPtr).getSt() == SymType.CON) {
65 | conDeclare();
66 | }
67 | if (allToken.get(tokenPtr).getSt() == SymType.VAR) {
68 | varDeclare();
69 | }
70 | if (allToken.get(tokenPtr).getSt() == SymType.PROC) {
71 | proc();
72 | }
73 |
74 | allPcode.getAllPcode().get(tmpPcodePtr).setA(allPcode.getPcodePtr()); //回填跳转地址
75 | allPcode.gen(Operator.INT, 0, address); //申请空间
76 | if (start != 0) {
77 | //如果不是主函数,则需要在符号表中的value填入该过程在Pcode代码中的起始位置
78 | allSymbol.getAllSymbol().get(pos).setValue(allPcode.getPcodePtr() - 1 - allSymbol.getAllSymbol().get(pos).getSize());
79 | }
80 |
81 | statement();
82 | allPcode.gen(Operator.OPR, 0, 0); //过程结束
83 |
84 | address = address_cp;
85 | }
86 |
87 | private void conDeclare() {
88 | //<常量说明部分>::=const <常量定义>{,<常量定义>}
89 | if (allToken.get(tokenPtr).getSt() == SymType.CON) {
90 | tokenPtr++;
91 | conHandle();
92 | while (allToken.get(tokenPtr).getSt() == SymType.COMMA || allToken.get(tokenPtr).getSt() == SymType.SYM) {
93 | if (allToken.get(tokenPtr).getSt() == SymType.COMMA) {
94 | tokenPtr++;
95 | } else {
96 | errorHandle(23, "");
97 | }
98 | conHandle();
99 | }
100 | if (allToken.get(tokenPtr).getSt() == SymType.SEMIC) {
101 | tokenPtr++;
102 | } else { //缺少;
103 | errorHandle(0, "");
104 | }
105 | } else { //缺少const
106 | errorHandle(-1, "");
107 | }
108 | }
109 |
110 | private void conHandle() {
111 | //<常量定义>::=<标识符>=<无符号整数>
112 | String name;
113 | int value;
114 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
115 | name = allToken.get(tokenPtr).getValue();
116 | tokenPtr++;
117 | if (allToken.get(tokenPtr).getSt() == SymType.EQU || allToken.get(tokenPtr).getSt() == SymType.CEQU) {
118 | if (allToken.get(tokenPtr).getSt() == SymType.CEQU) {
119 | errorHandle(3, "");
120 | }
121 | tokenPtr++;
122 | if (allToken.get(tokenPtr).getSt() == SymType.CONST) {
123 | value = Integer.parseInt(allToken.get(tokenPtr).getValue());
124 | if (allSymbol.isNowExists(name, level)) {
125 | errorHandle(15, name);
126 | }
127 | allSymbol.enterConst(name, level, value, address);
128 | //address += addIncrement;
129 | tokenPtr++;
130 | }
131 | } else { //赋值没用=
132 | errorHandle(3, "");
133 | }
134 | } else { //标识符不合法
135 | errorHandle(1, "");
136 | }
137 | }
138 |
139 | private void varDeclare() {
140 | //<变量说明部分>::=var<标识符>{,<标识符>}
141 | String name;
142 | int value;
143 | if (allToken.get(tokenPtr).getSt() == SymType.VAR) {
144 | tokenPtr++;
145 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
146 | name = allToken.get(tokenPtr).getValue();
147 | if (allSymbol.isNowExists(name, address)) {
148 | errorHandle(15, name);
149 | }
150 | allSymbol.enterVar(name, level, address);
151 | address += addIncrement;
152 | tokenPtr++;
153 | while (allToken.get(tokenPtr).getSt() == SymType.COMMA || allToken.get(tokenPtr).getSt() == SymType.SYM) {
154 | if (allToken.get(tokenPtr).getSt() == SymType.COMMA) {
155 | tokenPtr++;
156 | } else {
157 | errorHandle(23, "");
158 | }
159 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
160 | name = allToken.get(tokenPtr).getValue();
161 | if (allSymbol.isNowExists(name, address)) {
162 | errorHandle(15, name);
163 | }
164 | allSymbol.enterVar(name, level, address);
165 | address += addIncrement;
166 | tokenPtr++;
167 | } else { //非法标识符
168 | errorHandle(1, "");
169 | return;
170 | }
171 | }
172 | if (allToken.get(tokenPtr).getSt() != SymType.SEMIC) { //缺少;
173 | errorHandle(0, "");
174 | return;
175 | } else {
176 | tokenPtr++;
177 | }
178 | } else { //非法标识符
179 | errorHandle(1, "");
180 | return;
181 | }
182 | } else { //缺少var
183 | errorHandle(-1, "");
184 | return;
185 | }
186 | }
187 |
188 | private void proc() {
189 | //<过程说明部分>::=<过程首部><分程序>{;<过程说明部分>};
190 | //<过程首部>::=procedure<标识符>;
191 | if (allToken.get(tokenPtr).getSt() == SymType.PROC) {
192 | tokenPtr++;
193 | int count = 0; //记录参数个数
194 | int pos; //记录该过程在符号表中的位置
195 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
196 | String name = allToken.get(tokenPtr).getValue();
197 | if (allSymbol.isNowExists(name, level)) {
198 | errorHandle(15, name);
199 | }
200 | pos = allSymbol.getPtr();
201 | allSymbol.enterProc(name, level, address);
202 | address += addIncrement;
203 | level++;
204 | tokenPtr++;
205 | /*********不需要形式参数
206 | if (allToken.get(tokenPtr).getSt() == SymType.LBR) {
207 | tokenPtr++;
208 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
209 | allSymbol.enterVar(allToken.get(tokenPtr).getValue(), level, 3 + address);
210 | address += addIncrement;
211 | count++;
212 | allSymbol.getAllSymbol().get(pos).setSize(count);
213 | tokenPtr++;
214 | while (allToken.get(tokenPtr).getSt() == SymType.COMMA) {
215 | tokenPtr++;
216 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
217 | allSymbol.enterVar(allToken.get(tokenPtr).getValue(), level, 3 + address);
218 | address += addIncrement;
219 | count++;
220 | allSymbol.getAllSymbol().get(pos).setSize(count);
221 | tokenPtr++;
222 | } else {
223 | errorHandle(1, "");
224 | return;
225 | }
226 | }
227 | }
228 | if (allToken.get(tokenPtr).getSt() == SymType.RBR) {
229 | tokenPtr++;
230 | if (allToken.get(tokenPtr).getSt() != SymType.SEMIC) {
231 | errorHandle(0, "");
232 | return;
233 | } else {
234 | tokenPtr++;
235 | block();
236 | while (allToken.get(tokenPtr).getSt() == SymType.SEMIC) {
237 | tokenPtr++;
238 | proc();
239 | }
240 | }
241 | } else { //缺少)
242 | errorHandle(5, "");
243 | return;
244 | }
245 | } else { //缺少(
246 | errorHandle(4, "");
247 | return;
248 | }
249 | *************/
250 | if (allToken.get(tokenPtr).getSt() == SymType.SEMIC) {
251 | tokenPtr++;
252 | } else {
253 | errorHandle(0, "");
254 | }
255 | block();
256 | while (allToken.get(tokenPtr).getSt() == SymType.SEMIC || allToken.get(tokenPtr).getSt() == SymType.PROC) {
257 | if (allToken.get(tokenPtr).getSt() == SymType.SEMIC) {
258 | tokenPtr++;
259 | } else {
260 | errorHandle(0, "");
261 | }
262 | level--;
263 | proc();
264 | }
265 | } else {
266 | errorHandle(-1, "");
267 | return;
268 | }
269 | }
270 | }
271 |
272 | private void body() {
273 | //<复合语句>::=begin<语句>{;<语句>}end
274 | if (allToken.get(tokenPtr).getSt() == SymType.BEG) {
275 | tokenPtr++;
276 | statement();
277 | while (allToken.get(tokenPtr).getSt() == SymType.SEMIC || isHeadOfStatement()) {
278 | if (allToken.get(tokenPtr).getSt() == SymType.SEMIC) {
279 | tokenPtr++;
280 | } else {
281 | if (allToken.get(tokenPtr).getSt() != SymType.END) {
282 | errorHandle(0, "");
283 | }
284 | }
285 | if (allToken.get(tokenPtr).getSt() == SymType.END) {
286 | errorHandle(21, "");
287 | break;
288 | }
289 | statement();
290 | }
291 | if (allToken.get(tokenPtr).getSt() == SymType.END) {
292 | tokenPtr++;
293 | } else { //缺少end
294 | errorHandle(7, "");
295 | return;
296 | }
297 | } else { //缺少begin
298 | errorHandle(6, "");
299 | return;
300 | }
301 | }
302 |
303 | private void statement() {
304 | //<语句>::=<赋值语句> | <条件语句> | <当循环语句> | <过程调用语句> | <复合语句> | <读语句> | <写语句> | <空>
305 | if (allToken.get(tokenPtr).getSt() == SymType.IF) {
306 | //<条件语句>::=if<条件>then<语句>else<语句>
307 | tokenPtr++;
308 | condition();
309 | if (allToken.get(tokenPtr).getSt() == SymType.THEN) {
310 | int pos1 = allPcode.getPcodePtr();
311 | allPcode.gen(Operator.JPC, 0, 0);
312 | tokenPtr++;
313 | statement();
314 | int pos2 = allPcode.getPcodePtr();
315 | allPcode.gen(Operator.JMP, 0, 0);
316 | allPcode.getAllPcode().get(pos1).setA(allPcode.getPcodePtr());
317 | allPcode.getAllPcode().get(pos2).setA(allPcode.getPcodePtr());
318 | if (allToken.get(tokenPtr).getSt() == SymType.ELS) {
319 | tokenPtr++;
320 | statement();
321 | allPcode.getAllPcode().get(pos2).setA(allPcode.getPcodePtr());
322 | }
323 | } else {
324 | errorHandle(8, "");
325 | return;
326 | }
327 | } else if (allToken.get(tokenPtr).getSt() == SymType.WHI) {
328 | //<当循环语句>::=while<条件>do<语句>
329 | int pos1 = allPcode.getPcodePtr();
330 | tokenPtr++;
331 | condition();
332 | if (allToken.get(tokenPtr).getSt() == SymType.DO) {
333 | int pos2 = allPcode.getPcodePtr();
334 | allPcode.gen(Operator.JPC, 0, 0);
335 | tokenPtr++;
336 | statement();
337 | allPcode.gen(Operator.JMP, 0, pos1);
338 | allPcode.getAllPcode().get(pos2).setA(allPcode.getPcodePtr());
339 | } else {
340 | errorHandle(9, "");
341 | return;
342 | }
343 | } else if (allToken.get(tokenPtr).getSt() == SymType.CAL) {
344 | //<过程调用语句>::=call<标识符>
345 | tokenPtr++;
346 | int count = 0; //参数数目
347 | PerSymbol tmp;
348 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
349 | String name = allToken.get(tokenPtr).getValue();
350 | if (allSymbol.isPreExists(name, level)) {
351 | tmp = allSymbol.getSymbol(name);
352 | if (tmp.getType() == allSymbol.getProc()) {
353 | allPcode.gen(Operator.CAL, level - tmp.getLevel(), tmp.getValue());;
354 | } else {
355 | errorHandle(11, "");
356 | return;
357 | }
358 | } else { //不存在该过程
359 | errorHandle(10, "");
360 | return;
361 | }
362 | tokenPtr++;
363 | /**************过程调用不需要参数
364 | if (allToken.get(tokenPtr).getSt() == SymType.LBR) {
365 | tokenPtr++;
366 | if (allToken.get(tokenPtr).getSt() == SymType.RBR) {
367 | tokenPtr++;
368 | allPcode.gen(Operator.CAL, level - tmp.getLevel(), tmp.getValue());
369 | } else {
370 | expression();
371 | count++;
372 | while (allToken.get(tokenPtr).getSt() == SymType.COMMA) {
373 | tokenPtr++;
374 | expression();
375 | count++;
376 | }
377 | if (count != tmp.getSize()) {
378 | errorHandle(16, "");
379 | return;
380 | }
381 | allPcode.gen(Operator.CAL, level - tmp.getLevel(), tmp.getValue());
382 | if (allToken.get(tokenPtr).getSt() == SymType.RBR) {
383 | tokenPtr++;
384 | } else {
385 | errorHandle(5, "");
386 | return;
387 | }
388 | }
389 | } else {
390 | errorHandle(4, "");
391 | return;
392 | }
393 | **************/
394 | } else {
395 | errorHandle(1, "");
396 | return;
397 | }
398 | } else if (allToken.get(tokenPtr).getSt() == SymType.REA) {
399 | //<读语句>::=read'('<标识符>{,<标识符>}')'
400 | tokenPtr++;
401 | if (allToken.get(tokenPtr).getSt() == SymType.LBR) {
402 | tokenPtr++;
403 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
404 | String name = allToken.get(tokenPtr).getValue();
405 | if (!allSymbol.isPreExists(name, level)) {
406 | errorHandle(10, "");
407 | return;
408 | } else {
409 | PerSymbol tmp = allSymbol.getSymbol(name);
410 | if (tmp.getType() == allSymbol.getVar()) {
411 | allPcode.gen(Operator.OPR, 0, 16);
412 | allPcode.gen(Operator.STO, level - tmp.getLevel(), tmp.getAddress());
413 | } else {
414 | errorHandle(12, "");
415 | return;
416 | }
417 | }
418 | }
419 | tokenPtr++;
420 | while (allToken.get(tokenPtr).getSt() == SymType.COMMA) {
421 | tokenPtr++;
422 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
423 | String name = allToken.get(tokenPtr).getValue();
424 | if (!allSymbol.isPreExists(name, level)) {
425 | errorHandle(10, "");
426 | return;
427 | } else {
428 | PerSymbol tmp = allSymbol.getSymbol(name);
429 | if (tmp.getType() == allSymbol.getVar()) {
430 | allPcode.gen(Operator.OPR, 0, 16);
431 | allPcode.gen(Operator.STO, level - tmp.getLevel(), tmp.getAddress());
432 | } else {
433 | errorHandle(12, "");
434 | return;
435 | }
436 | }
437 | tokenPtr++;
438 | } else {
439 | errorHandle(1, "");
440 | return;
441 | }
442 | }
443 | if (allToken.get(tokenPtr).getSt() == SymType.RBR) {
444 | tokenPtr++;
445 | } else {
446 | errorHandle(5, "");
447 | return;
448 | }
449 | } else {
450 | errorHandle(4, "");
451 | return;
452 | }
453 | } else if (allToken.get(tokenPtr).getSt() == SymType.WRI) {
454 | //<写语句>::=write '('<表达式>{,<表达式>}')'
455 | tokenPtr++;
456 | if (allToken.get(tokenPtr).getSt() == SymType.LBR) {
457 | tokenPtr++;
458 | expression();
459 | allPcode.gen(Operator.OPR, 0, 14);
460 | while (allToken.get(tokenPtr).getSt() == SymType.COMMA) {
461 | tokenPtr++;
462 | expression();
463 | allPcode.gen(Operator.OPR, 0, 14);
464 | }
465 | allPcode.gen(Operator.OPR, 0, 15);
466 | if (allToken.get(tokenPtr).getSt() == SymType.RBR) {
467 | tokenPtr++;
468 | } else { //缺少)
469 | errorHandle(5, "");
470 | return;
471 | }
472 | } else { //缺少(
473 | errorHandle(4, "");
474 | }
475 | } else if (allToken.get(tokenPtr).getSt() == SymType.BEG) {
476 | //<复合语句>::=begin<语句>{;<语句>}end
477 | body();
478 | } else if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
479 | //<赋值语句>::=<标识符>:=<表达式>
480 | String name = allToken.get(tokenPtr).getValue();
481 | tokenPtr++;
482 | if (allToken.get(tokenPtr).getSt() == SymType.CEQU || allToken.get(tokenPtr).getSt() == SymType.EQU || allToken.get(tokenPtr).getSt() == SymType.COL) {
483 | if (allToken.get(tokenPtr).getSt() == SymType.EQU || allToken.get(tokenPtr).getSt() == SymType.COL) {
484 | errorHandle(3, "");
485 | }
486 | tokenPtr++;
487 | expression();
488 | if (!allSymbol.isPreExists(name, level)) {
489 | errorHandle(14, name);
490 | return;
491 | } else {
492 | PerSymbol tmp = allSymbol.getSymbol(name);
493 | if (tmp.getType() == allSymbol.getVar()) {
494 | allPcode.gen(Operator.STO, level - tmp.getLevel(), tmp.getAddress());
495 | } else {
496 | errorHandle(13, name);
497 | return;
498 | }
499 | }
500 | } else {
501 | errorHandle(3, "");
502 | return;
503 | }
504 | } else if (allToken.get(tokenPtr).getSt() == SymType.REP) {
505 | //<重复语句> ::= repeat<语句>{;<语句>}until<条件>
506 | tokenPtr++;
507 | int pos = allPcode.getPcodePtr();
508 | statement();
509 | while (allToken.get(tokenPtr).getSt() == SymType.SEMIC || isHeadOfStatement()) {
510 | if (isHeadOfStatement()) {
511 | errorHandle(1, "");
512 | } else {
513 | tokenPtr++;
514 | }
515 | if (allToken.get(tokenPtr).getSt() == SymType.UNT) {
516 | errorHandle(22, "");
517 | break;
518 | }
519 | tokenPtr++;
520 | statement();
521 | }
522 | if (allToken.get(tokenPtr).getSt() == SymType.UNT) {
523 | tokenPtr++;
524 | condition();
525 | allPcode.gen(Operator.JPC, 0, pos);
526 | } else {
527 | errorHandle(19, "");
528 | return;
529 | }
530 | } else {
531 | errorHandle(1, "");
532 | return;
533 | }
534 | }
535 |
536 | private void condition() {
537 | //<条件>::=<表达式><关系运算符><表达式> | odd<表达式>
538 | if (allToken.get(tokenPtr).getSt() == SymType.ODD) {
539 | allPcode.gen(Operator.OPR, 0, 6);
540 | tokenPtr++;
541 | expression();
542 | } else {
543 | expression();
544 | SymType tmp = allToken.get(tokenPtr).getSt();
545 | tokenPtr++;
546 | expression();
547 | if (tmp == SymType.EQU) { //两个结果是否相等
548 | allPcode.gen(Operator.OPR, 0, 8);
549 | } else if (tmp == SymType.NEQE) { //两个结果是否不等
550 | allPcode.gen(Operator.OPR, 0, 9);
551 | } else if (tmp == SymType.LES) { //小于
552 | allPcode.gen(Operator.OPR, 0, 10);
553 | } else if (tmp == SymType.LARE) { //大于等于
554 | allPcode.gen(Operator.OPR, 0, 11);
555 | } else if (tmp == SymType.LAR) { //大于
556 | allPcode.gen(Operator.OPR, 0, 12);
557 | } else if (tmp == SymType.LESE) { //小于等于
558 | allPcode.gen(Operator.OPR, 0, 13);
559 | } else { //不合法的比较运算符
560 | errorHandle(2, "");
561 | }
562 | }
563 | }
564 |
565 | private void expression() {
566 | //<表达式>::=[+|-]<项>{<加法运算符><项>}
567 | //<加法运算符>::=+|-
568 | SymType tmp = allToken.get(tokenPtr).getSt();
569 | if (tmp == SymType.ADD || tmp == SymType.SUB) {
570 | tokenPtr++;
571 | }
572 | term();
573 | if (tmp == SymType.SUB) {
574 | allPcode.gen(Operator.OPR, 0, 1);
575 | }
576 | while (allToken.get(tokenPtr).getSt() == SymType.ADD || allToken.get(tokenPtr).getSt() == SymType.SUB) {
577 | tmp = allToken.get(tokenPtr).getSt();
578 | tokenPtr++;
579 | term();
580 | if (tmp == SymType.ADD) {
581 | allPcode.gen(Operator.OPR, 0, 2);
582 | } else if (tmp == SymType.SUB) {
583 | allPcode.gen(Operator.OPR, 0, 3);
584 | }
585 | }
586 | }
587 |
588 | private void term() {
589 | //<项>::=<因子>{<乘法运算符><因子>}
590 | //<乘法运算符>::=*|/
591 | factor();
592 | while (allToken.get(tokenPtr).getSt() == SymType.MUL || allToken.get(tokenPtr).getSt() == SymType.DIV) {
593 | SymType tmp = allToken.get(tokenPtr).getSt();
594 | tokenPtr++;
595 | factor();
596 | if (tmp == SymType.MUL) {
597 | allPcode.gen(Operator.OPR, 0, 4);
598 | } else if (tmp == SymType.DIV) {
599 | allPcode.gen(Operator.OPR, 0, 5);
600 | }
601 | }
602 | }
603 |
604 | private void factor() {
605 | //<因子>::=<标识符> | <无符号整数> | '('<表达式>')'
606 | if (allToken.get(tokenPtr).getSt() == SymType.CONST) {
607 | allPcode.gen(Operator.LIT, 0, Integer.parseInt(allToken.get(tokenPtr).getValue()));
608 | tokenPtr++;
609 | } else if (allToken.get(tokenPtr).getSt() == SymType.LBR) {
610 | tokenPtr++;
611 | expression();
612 | if (allToken.get(tokenPtr).getSt() == SymType.RBR) {
613 | tokenPtr++;
614 | } else { //缺少右括号
615 | errorHandle(5, "");
616 | }
617 | } else if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
618 | String name = allToken.get(tokenPtr).getValue();
619 | if (! allSymbol.isPreExists(name, level)) {
620 | errorHandle(10, "");
621 | return;
622 | } else {
623 | PerSymbol tmp = allSymbol.getSymbol(name);
624 | if (tmp.getType() == allSymbol.getVar()) {
625 | allPcode.gen(Operator.LOD, level - tmp.getLevel(), tmp.getAddress());
626 | } else if (tmp.getType() == allSymbol.getCon()) {
627 | allPcode.gen(Operator.LIT, 0, tmp.getValue());
628 | } else {
629 | errorHandle(12, "");
630 | return;
631 | }
632 | }
633 | tokenPtr++;
634 | } else {
635 | errorHandle(1, "");
636 | return;
637 | }
638 | }
639 |
640 | private boolean isHeadOfStatement() {
641 | return (allToken.get(tokenPtr).getSt() == SymType.IF ||
642 | allToken.get(tokenPtr).getSt() == SymType.WHI ||
643 | allToken.get(tokenPtr).getSt() == SymType.CAL ||
644 | allToken.get(tokenPtr).getSt() == SymType.REA ||
645 | allToken.get(tokenPtr).getSt() == SymType.WRI ||
646 | allToken.get(tokenPtr).getSt() == SymType.BEG ||
647 | allToken.get(tokenPtr).getSt() == SymType.SYM ||
648 | allToken.get(tokenPtr).getSt() == SymType.REP);
649 | }
650 |
651 | private void errorHandle(int k, String name) {
652 | errorHappen = true;
653 | String error = "";
654 | switch(k) {
655 | case -1: //常量定义不是const开头,变量定义不是var开头
656 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "wrong token";
657 | break;
658 | case 0: //缺少分号
659 | if (allToken.get(tokenPtr).getSt() == SymType.SYM) {
660 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing ; before " + allToken.get(tokenPtr).getValue();
661 | } else {
662 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing ; before " + allToken.get(tokenPtr).getSt();
663 | }
664 | break;
665 | case 1: //标识符不合法
666 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Identifier illegal";
667 | break;
668 | case 2: //不合法的比较符
669 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "illegal compare symbol";
670 | break;
671 | case 3: //常量赋值没用=
672 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Const assign must be =";
673 | break;
674 | case 4: //缺少(
675 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing (";
676 | break;
677 | case 5: //缺少)
678 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missind )";
679 | break;
680 | case 6: //缺少begin
681 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing begin";
682 | break;
683 | case 7: //缺少end
684 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing end";
685 | break;
686 | case 8: //缺少then
687 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing then";
688 | break;
689 | case 9: //缺少do
690 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing do";
691 | break;
692 | case 10: //call, write, read语句中,不存在标识符
693 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Not exist" + allToken.get(tokenPtr).getValue();
694 | break;
695 | case 11: //该标识符不是proc类型
696 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + allToken.get(tokenPtr).getValue() + "is not a procedure";
697 | break;
698 | case 12: //read, write语句中,该标识符不是var类型
699 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + allToken.get(tokenPtr).getValue() + "is not a variable";
700 | break;
701 | case 13: //赋值语句中,该标识符不是var类型
702 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + name + "is not a varible";
703 | break;
704 | case 14: //赋值语句中,该标识符不存在
705 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "not exist " + name;
706 | break;
707 | case 15: //该标识符已存在
708 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Already exist " + name;
709 | break;
710 | case 16: //调用函数参数错误
711 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Number of parameters of procedure " + name + "is incorrect";
712 | break;
713 | case 17: //缺少.
714 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing .";
715 | break;
716 | case 18: //多余代码
717 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "too much code after .";
718 | break;
719 | case 19: //缺少until
720 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing until";
721 | break;
722 | case 20: //赋值符应为:=
723 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Assign must be :=";
724 | break;
725 | case 21: //end前多了;
726 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "; is no need before end";
727 | break;
728 | case 22: //until前多了;
729 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "; is no need before ubtil";
730 | break;
731 | case 23: //缺少,
732 | error = "Error happened in line " + allToken.get(tokenPtr).getLine() + ":" + "Missing ,";
733 | break;
734 | }
735 | errorMessage.add(error);
736 | }
737 |
738 | public List getErrorMessage() {
739 | return errorMessage;
740 | }
741 |
742 | public void showAllToken() {
743 | for (int i = 0; i < allToken.size(); i++) {
744 | System.out.println(allToken.get(i).getSt() + " " + allToken.get(i).getLine() + " " + allToken.get(i).getValue());
745 | }
746 | }
747 |
748 | public List getAllToken() {
749 | return allToken;
750 | }
751 |
752 | public void showAllSymbol() {
753 | List display = allSymbol.getAllSymbol();
754 | for (int i = 0; i < display.size(); i++) {
755 | System.out.println(display.get(i).getType() + " " +
756 | display.get(i).getName() + " " +
757 | display.get(i).getValue() + " " +
758 | display.get(i).getLevel() + " " +
759 | display.get(i).getAddress());
760 | }
761 | }
762 |
763 | public List getAllSymbol() {
764 | return allSymbol.getAllSymbol();
765 | }
766 |
767 | public void showAllPcode() {
768 | List display = allPcode.getAllPcode();
769 | for (int i = 0; i < display.size(); i++) {
770 | System.out.print(i + " " + display.get(i).getF() + " ");
771 | System.out.println(" " + display.get(i).getL() + " " +display.get(i).getA());
772 | }
773 | }
774 |
775 | public List getAllPcode() {
776 | return allPcode.getAllPcode();
777 | }
778 |
779 | public List interpreter(List input) {
780 | Interpreter one = new Interpreter(input);
781 | one.setAllPcode(allPcode);
782 | one.interpreter();
783 | return one.getOutput();
784 | }
785 |
786 | public void interpreter() {
787 | Interpreter one = new Interpreter();
788 | one.setAllPcode(allPcode);
789 | one.interpreter();
790 | }
791 | }
792 |
--------------------------------------------------------------------------------
/src/Interpreter.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 | import java.util.Scanner;
4 |
5 | public class Interpreter {
6 | private int STACK_SIZE = 1000;
7 | private int[] dataStack = new int[STACK_SIZE];
8 | private List pcode;
9 | private List input;
10 | private int inputPtr;
11 | private List output;
12 |
13 | public Interpreter() {
14 |
15 | }
16 |
17 | public Interpreter(List _input) {
18 | input = _input;
19 | output = new ArrayList();
20 | }
21 |
22 | public void setAllPcode(AllPcode allPcode) {
23 | pcode = allPcode.getAllPcode();
24 | }
25 |
26 | public List getOutput() {
27 | return output;
28 | }
29 |
30 | public void interpreter() {
31 | int pc = 0; //程序计数器,指向下一条指令
32 | int base = 0; //当前基地址
33 | int top = 0; //程序运行栈栈顶
34 | do {
35 | PerPcode currentPcode = pcode.get(pc);
36 | pc++;
37 | if (currentPcode.getF() == Operator.LIT) {
38 | //LIT:将常量送到运行栈S的栈顶,这时A段为常量值
39 | dataStack[top] = currentPcode.getA();
40 | top++;
41 | } else if (currentPcode.getF() == Operator.OPR) {
42 | //OPR:关系或算术运算,A段指明具体运算
43 | switch(currentPcode.getA()) {
44 | case 0:
45 | //OPR 0 0 过程调用结束后,返回调用点并退栈
46 | top = base;
47 | pc = dataStack[base + 2];
48 | base = dataStack[base];
49 | break;
50 | case 1:
51 | //OPR 0 1 栈顶元素取反
52 | dataStack[top - 1] = -dataStack[top - 1];
53 | break;
54 | case 2:
55 | //OPR 0 2 次栈顶与栈顶相加,退两个栈元素,结果值进栈
56 | dataStack[top - 2] = dataStack[top - 1] + dataStack[top - 2];
57 | top--;
58 | break;
59 | case 3:
60 | //OPR 0 3 次栈顶减去栈顶,退两个栈元素,结果值进栈
61 | dataStack[top - 2] = dataStack[top - 2] - dataStack[top - 1];
62 | top--;
63 | break;
64 | case 4:
65 | //OPR 0 4 次栈顶乘以栈顶,退两个栈元素,结果值进栈
66 | dataStack[top - 2] = dataStack[top - 1] * dataStack[top - 2];
67 | top--;
68 | break;
69 | case 5:
70 | //OPR 0 5 次栈顶除以栈顶,退两个栈元素,结果值进栈
71 | dataStack[top - 2] = dataStack[top - 2] / dataStack[top - 1];
72 | top--;
73 | break;
74 | case 6:
75 | //OPR 0 6 栈顶元素的奇偶判断,结果值在栈顶
76 | dataStack[top - 1] = dataStack[top - 1] % 2;
77 | break;
78 | case 7:
79 | break;
80 | case 8:
81 | //OPR 0 8 次栈顶与栈顶是否相等,退两个栈元素,结果值进栈
82 | if (dataStack[top - 2] == dataStack[top - 1]) {
83 | dataStack[top - 2] = 1;
84 | } else {
85 | dataStack[top - 2] = 0;
86 | }
87 | top--;
88 | break;
89 | case 9:
90 | //OPR 0 9 次栈顶与栈顶是否不等,退两个栈元素,结果值进栈
91 | if (dataStack[top - 2] != dataStack[top - 1]) {
92 | dataStack[top - 2] = 1;
93 | } else {
94 | dataStack[top - 2] = 0;
95 | }
96 | top--;
97 | break;
98 | case 10:
99 | //OPR 0 10 次栈顶是否小于栈顶,退两个栈元素,结果值进栈
100 | if (dataStack[top - 2] < dataStack[top - 1]) {
101 | dataStack[top - 2] = 1;
102 | } else {
103 | dataStack[top - 2] = 0;
104 | }
105 | top--;
106 | break;
107 | case 11:
108 | //OPR 0 11 次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈
109 | if (dataStack[top - 2] >= dataStack[top - 1]) {
110 | dataStack[top - 2] = 1;
111 | } else {
112 | dataStack[top - 2] = 0;
113 | }
114 | top--;
115 | break;
116 | case 12:
117 | //OPR 0 12 次栈顶是否大于栈顶,退两个栈元素,结果值进栈
118 | if (dataStack[top - 2] > dataStack[top - 1]) {
119 | dataStack[top - 2] = 1;
120 | } else {
121 | dataStack[top - 2] = 0;
122 | }
123 | top--;
124 | break;
125 | case 13:
126 | //OPR 0 13 次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈
127 | if (dataStack[top - 2] <= dataStack[top - 1]) {
128 | dataStack[top - 2] = 1;
129 | } else {
130 | dataStack[top - 2] = 0;
131 | }
132 | top--;
133 | break;
134 | case 14:
135 | //OPR 0 14 栈顶值输出至屏幕
136 | System.out.print(dataStack[top - 1]);
137 | System.out.print(" ");
138 | //output.add(dataStack[top - 1] + " ");
139 | break;
140 | case 15:
141 | //OPR 0 15 屏幕输出换行
142 | System.out.println();
143 | //output.add("\n");
144 | break;
145 | case 16:
146 | //OPR 0 16 从命令行读入一个输入置于栈顶
147 | System.out.println("please input a number");
148 | Scanner s = new Scanner(System.in);
149 | dataStack[top] = s.nextInt();
150 | //dataStack[top] = input.get(inputPtr++);
151 | top++;
152 | break;
153 | }
154 | } else if (currentPcode.getF() == Operator.LOD) {
155 | // LOD:将变量送到运行栈S的栈顶,这时A段为变量所在说明层中的相对位置。
156 | dataStack[top] = dataStack[currentPcode.getA() + getBase(base, currentPcode.getL())];
157 | top++;
158 | } else if (currentPcode.getF() == Operator.STO) {
159 | //STO:将运行栈S的栈顶内容送入某个变量单元中,A段为变量所在说明层中的相对位置。
160 | dataStack[currentPcode.getA() + getBase(base, currentPcode.getL())] = dataStack[top - 1];
161 | top--;
162 | } else if (currentPcode.getF() == Operator.CAL) {
163 | //CAL:调用过程,这时A段为被调用过程的过程体(过程体之前一条指令)在目标程序区的入口地址。
164 | //跳转时,将该层基地址,跳转层基地址,pc指针保存在栈中
165 | //基地址base变为此时栈顶top,pc指向要跳转的地方
166 | //不修改top,因为前面代码已经将address+3,生成Pcode后会产生INT语句,修改top值
167 | dataStack[top] = base;
168 | dataStack[top + 1] = getBase(base, currentPcode.getL());
169 | dataStack[top + 2] = pc;
170 | base = top;
171 | pc = currentPcode.getA();
172 | } else if (currentPcode.getF() == Operator.INT) {
173 | //INT:为被调用的过程(包括主过程)在运行栈S中开辟数据区,这时A段为所需数据单元个数(包括三个连接数据);L段恒为0。
174 | top = top + currentPcode.getA();
175 | } else if (currentPcode.getF() == Operator.JMP) {
176 | //JMP:无条件转移,这时A段为转向地址(目标程序)。
177 | pc = currentPcode.getA();
178 | } else if (currentPcode.getF() == Operator.JPC) {
179 | //JPC:条件转移,当运行栈S的栈顶的布尔值为假(0)时,则转向A段所指目标程序地址;否则顺序执行。
180 | if (dataStack[top - 1] == 0) {
181 | pc = currentPcode.getA();
182 | }
183 | }
184 | //System.out.println(pc + " " + base + " " + top);
185 | } while (pc != 0);
186 | }
187 |
188 | //已知该层基地址为nowBp,得到层差为lev的层的基地址
189 | private int getBase(int nowBp,int lev) {
190 | int oldBp = nowBp;
191 | while (lev > 0) {
192 | oldBp = dataStack[oldBp + 1];
193 | lev--;
194 | }
195 | return oldBp;
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/src/LexAnalysis.java:
--------------------------------------------------------------------------------
1 | import java.io.BufferedReader;
2 | import java.io.File;
3 | import java.io.FileNotFoundException;
4 | import java.io.FileReader;
5 | import java.io.IOException;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /**
10 | * created by shiyi on 2016/12/14
11 | * 词法分析程序
12 | */
13 |
14 | public class LexAnalysis {
15 | private String[] keyWords = {
16 | "begin", "end", "if", "then", "else", "const", "procedure", "var", "do", "while", "call", "read", "write", "odd", "repeat", "until"
17 | };
18 |
19 | private List allToken; //存放所有分析出来的token
20 | private char ch = ' '; //当前字符
21 | private int searchPtr = 0; //指向当前字符的指针
22 | private char[] buffer; //存放所有源代码
23 | private int line = 1; //当前行
24 | private String strToken; //当前正在进行词法分析的字符串
25 |
26 | public LexAnalysis(File file) {
27 | init();
28 | BufferedReader bf = null;
29 | try {
30 | bf = new BufferedReader(new FileReader(file));
31 | String temp1 = "", temp2 = "";
32 | while((temp1 = bf.readLine()) != null) {
33 | temp2 = temp2 + temp1 + String.valueOf('\n');
34 | }
35 | buffer = temp2.toCharArray();
36 | bf.close();
37 | } catch (FileNotFoundException e) {
38 | e.printStackTrace();
39 | } catch (IOException e) {
40 | e.printStackTrace();
41 | }
42 | doAnalysis();
43 | }
44 |
45 | public List getAllToken() {
46 | return allToken;
47 | }
48 |
49 | private void doAnalysis() {
50 | while (searchPtr < buffer.length) {
51 | //Token one = analysis();
52 | //System.out.println(one.getSt() + " " + one.getLine() + " " + one.getValue());
53 | allToken.add(analysis());
54 | }
55 | }
56 |
57 | private Token analysis() {
58 | strToken = "";
59 | getChar();
60 | while ((ch == ' ' || ch == '\n' || ch == '\t' || ch == '\0') && searchPtr < buffer.length) {
61 | if (ch == '\n') {
62 | line++;
63 | }
64 | getChar();
65 | }
66 | if (ch == '$' && searchPtr >= buffer.length) { //到达文件末尾
67 | return new Token(SymType.EOF, line, "-1");
68 | }
69 | if (isLetter()) { //首位为字母,可能为保留字或者变量名
70 | while (isLetter() || isDigit()) {
71 | strToken += ch;
72 | getChar();
73 | }
74 | retract();
75 | for (int i = 0; i < keyWords.length; i++) {
76 | if (strToken.equals(keyWords[i])) { //说明是保留字
77 | return new Token(SymType.values()[i], line, "-");
78 | }
79 | }
80 | //不是保留字,则为标识符,需要保存值
81 | return new Token(SymType.SYM, line, strToken);
82 | } else if (isDigit()) { //首位为数字,即为整数
83 | while (isDigit()) {
84 | strToken += ch;
85 | getChar();
86 | }
87 | retract();
88 | return new Token(SymType.CONST, line, strToken);
89 | } else if (ch == '=') { //等号
90 | return new Token(SymType.EQU, line, "-");
91 | } else if (ch == '+') { //加号
92 | return new Token(SymType.ADD, line, "-");
93 | } else if (ch == '-') { //减号
94 | return new Token(SymType.SUB, line, "-");
95 | } else if (ch == '*') { //乘号
96 | return new Token(SymType.MUL, line, "-");
97 | } else if (ch == '/') { //除号
98 | return new Token(SymType.DIV, line, "-");
99 | } else if (ch == '<') { //小于或不等于或小于等于
100 | getChar();
101 | if (ch == '=') {
102 | return new Token(SymType.LESE, line, "-");
103 | } else if (ch == '>') {
104 | return new Token(SymType.NEQE, line, "-");
105 | } else {
106 | retract();
107 | return new Token(SymType.LES, line, "-");
108 | }
109 | } else if (ch == '>') { //大于或大于等于
110 | getChar();
111 | if (ch == '=') {
112 | return new Token(SymType.LARE, line, "-");
113 | } else {
114 | retract();
115 | return new Token(SymType.LAR, line, "-");
116 | }
117 | } else if (ch == ',') { //逗号
118 | return new Token(SymType.COMMA, line, "-");
119 | } else if (ch == ';') { //分号
120 | return new Token(SymType.SEMIC, line, "-");
121 | } else if (ch == '.') { //点
122 | return new Token(SymType.POI, line, "-");
123 | } else if (ch == '(') { //左括号
124 | return new Token(SymType.LBR, line, "-");
125 | } else if (ch == ')') { //右括号
126 | return new Token(SymType.RBR, line, "-");
127 | } else if (ch == ':') { //赋值号
128 | getChar();
129 | if (ch == '=') {
130 | return new Token(SymType.CEQU, line, "-");
131 | } else {
132 | retract();
133 | return new Token(SymType.COL, line, "-");
134 | }
135 | }
136 | return new Token(SymType.EOF, line, "-");
137 | }
138 |
139 | private void init() {
140 | allToken = new ArrayList();
141 | }
142 |
143 | private char getChar() {
144 | if (searchPtr < buffer.length) {
145 | ch = buffer[searchPtr];
146 | searchPtr++;
147 | } else {
148 | ch = '$';
149 | }
150 | return ch;
151 | }
152 |
153 | private void retract() {
154 | searchPtr--;
155 | ch = ' ';
156 | }
157 |
158 | private boolean isLetter() {
159 | if(Character.isLetter(ch)) {
160 | return true;
161 | }
162 | return false;
163 | }
164 |
165 | private boolean isDigit() {
166 | if(Character.isDigit(ch)) {
167 | return true;
168 | }
169 | return false;
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/src/MyCompiler.java:
--------------------------------------------------------------------------------
1 | import java.awt.BorderLayout;
2 | import java.awt.Dimension;
3 | import java.awt.FileDialog;
4 | import java.awt.Font;
5 | import java.awt.GridLayout;
6 | import java.awt.event.ActionEvent;
7 | import java.awt.event.ActionListener;
8 | import java.io.BufferedReader;
9 | import java.io.BufferedWriter;
10 | import java.io.File;
11 | import java.io.FileReader;
12 | import java.io.FileWriter;
13 | import java.io.IOException;
14 | import java.util.ArrayList;
15 | import java.util.List;
16 | import java.util.Scanner;
17 |
18 | import javax.swing.JFileChooser;
19 | import javax.swing.JFrame;
20 | import javax.swing.JMenu;
21 | import javax.swing.JMenuBar;
22 | import javax.swing.JMenuItem;
23 | import javax.swing.JOptionPane;
24 | import javax.swing.JPanel;
25 | import javax.swing.JScrollPane;
26 | import javax.swing.JTable;
27 | import javax.swing.JTextArea;
28 | import javax.swing.table.DefaultTableModel;
29 | import javax.swing.table.TableModel;
30 |
31 | public class MyCompiler extends JFrame{
32 |
33 | private JMenuBar menuBar;
34 | private JMenu fileMenu;
35 | private JMenu projectMenu;
36 | private JMenu helpMenu;
37 | private JTextArea jTextArea;
38 | private JScrollPane jScrollPane;
39 | private JMenuItem openItem, closeItem, saveItem,aboutItem;
40 | private JMenuItem compileItem, runItem;
41 |
42 | private FileDialog open,save;
43 | private File file;
44 |
45 | private JPanel tablePanel; //放置所有表格
46 | //token表格
47 | private JScrollPane tokenJScrollPane;
48 | private JTable tokenTable;
49 | String[] tokenColumnNames = {"符号类型","所在行", "符号值"};
50 | private TableModel tokenTableModel = new DefaultTableModel(tokenColumnNames, 0);
51 |
52 | //symbol表格
53 | private JScrollPane symbolJScrollPane;
54 | private JTable symbolTable;
55 | String[] symbolColumnNames = {"变量名", "变量类型", "变量值", "变量层次", "变量地址"};
56 | private TableModel symbolTableModel = new DefaultTableModel(symbolColumnNames, 0);
57 |
58 | //pcode表格
59 | private JScrollPane pcodeJScrollPane;
60 | private JTable pcodeTable;
61 | String[] pcodeColumnNames = {"F", "L", "A"};
62 | private TableModel pcodeTableModel = new DefaultTableModel(pcodeColumnNames, 0);
63 |
64 | private JTextArea errorMessage;
65 | private JScrollPane errorPane;
66 |
67 | private GSAnalysis gsa;
68 | private List allToken;
69 | private List allSymbol;
70 | private List allPcode;
71 | private List errors;
72 | private String consoleMessage;
73 | private int readNum = 0;
74 | private List output;
75 | private boolean success = false;
76 |
77 | public MyCompiler() {
78 | init();
79 | }
80 |
81 | private void init() {
82 | JFrame frame = new JFrame("PL0Compiler");
83 | frame.setBounds(300, 300, 700, 450);
84 | frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
85 |
86 | menuBar = new JMenuBar();//菜单栏
87 | fileMenu = new JMenu("文件");
88 | projectMenu = new JMenu("项目");
89 | helpMenu = new JMenu("帮助");
90 |
91 | jTextArea = new JTextArea(10, 40);
92 | jTextArea.setFont(new Font("Monospaced",1,20));
93 | jTextArea.setLineWrap(true);//到达指定宽度则换行
94 | //应当首先利用构造函数指定JScrollPane的控制对象,此处为JTextArea,然后再添加JScrollPane
95 | //添加进面板
96 | jScrollPane = new JScrollPane(jTextArea);
97 | //设置滚动条自动出现
98 | jScrollPane.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
99 | jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
100 | jScrollPane.setViewportView(jTextArea);
101 | openItem = new JMenuItem("打开");
102 | saveItem = new JMenuItem("保存");
103 | closeItem = new JMenuItem("关闭");
104 | aboutItem = new JMenuItem("关于");
105 | compileItem = new JMenuItem("编译");
106 | runItem = new JMenuItem("运行");
107 |
108 | //添加两个选项卡到JMenu
109 | //添加字菜单项到菜单项
110 | menuBar.add(fileMenu);
111 | menuBar.add(projectMenu);
112 | menuBar.add(helpMenu);
113 | fileMenu.add(openItem);
114 | fileMenu.add(saveItem);
115 | fileMenu.add(closeItem);
116 | projectMenu.add(compileItem);
117 | projectMenu.add(runItem);
118 | helpMenu.add(aboutItem);
119 |
120 | //设置token表格
121 | tokenTable = new JTable(tokenTableModel);
122 | tokenTable.setPreferredScrollableViewportSize(new Dimension(300, 100));
123 | tokenTable.setFillsViewportHeight(true);
124 | tokenJScrollPane = new JScrollPane(tokenTable);
125 |
126 | //设置symbbol表格
127 | symbolTable = new JTable(symbolTableModel);
128 | symbolTable.setPreferredScrollableViewportSize(new Dimension(300, 100));
129 | symbolTable.setFillsViewportHeight(true);
130 | symbolJScrollPane = new JScrollPane(symbolTable);
131 |
132 | //设置pcode表格
133 | pcodeTable = new JTable(pcodeTableModel);
134 | pcodeTable.setPreferredScrollableViewportSize(new Dimension(300, 100));
135 | pcodeTable.setFillsViewportHeight(true);
136 | pcodeJScrollPane = new JScrollPane(pcodeTable);
137 |
138 | tablePanel = new JPanel();
139 | tablePanel.setLayout( new GridLayout (0, 1));
140 | tablePanel.add(tokenJScrollPane);
141 | tablePanel.add(symbolJScrollPane);
142 | tablePanel.add(pcodeJScrollPane);
143 |
144 | //出错信息
145 | errorMessage = new JTextArea();
146 | errorPane = new JScrollPane(errorMessage);
147 | errorPane.setPreferredSize(new Dimension(700, 100));
148 |
149 | //放置菜单项及输入框
150 | frame.add(menuBar, BorderLayout.NORTH);
151 | frame.add(jScrollPane, BorderLayout.CENTER);
152 | frame.add(tablePanel, BorderLayout.EAST);
153 | frame.add(errorPane, BorderLayout.SOUTH);
154 |
155 | open = new FileDialog(frame,"打开文档",FileDialog.LOAD);
156 | save = new FileDialog(frame,"保存文档",FileDialog.SAVE);
157 |
158 | Event();
159 | frame.setVisible(true);
160 | }
161 |
162 | private void Event() {
163 | closeItem.addActionListener(new ActionListener() {
164 | @Override
165 | public void actionPerformed(ActionEvent e) {
166 | System.exit(0);
167 | }
168 | });
169 |
170 | aboutItem.addActionListener(new ActionListener() {
171 | @Override
172 | public void actionPerformed(ActionEvent e) {
173 | JOptionPane.showMessageDialog(null, "PL0Compiler\n"
174 | + "made by shiyi001\ni_am_shiyi@163.com");
175 | }
176 | });
177 |
178 | openItem.addActionListener(new ActionListener() {//菜单条目监听:打开
179 | public void actionPerformed(ActionEvent e) {
180 | open.setVisible(true);
181 |
182 | String dirPath = open.getDirectory();
183 | String fileName = open.getFile();
184 | if (dirPath == null || fileName == null) {
185 | return;
186 | }
187 | file = new File(dirPath, fileName);
188 |
189 | jTextArea.setText("");//打开文件之前清空文本区域
190 |
191 | try {
192 | BufferedReader br = new BufferedReader(new FileReader(file));
193 | String line = null;
194 | while ((line = br.readLine()) != null) {
195 | //将给定文本追加到文档结尾。如果模型为 null 或者字符串为 null 或空,则不执行任何操作。
196 | //虽然大多数 Swing 方法不是线程安全的,但此方法是线程安全的。
197 | jTextArea.append(line + "\r\n");
198 | }
199 | }
200 | catch (IOException ex) {
201 | throw new RuntimeException("读取失败!");
202 | }
203 | }
204 | });
205 |
206 | saveItem.addActionListener(new ActionListener() {//菜单条目监听:保存
207 | public void actionPerformed(ActionEvent e) {
208 | if (file == null) {
209 | newFile();
210 | }
211 | saveFile();
212 | }
213 | });
214 |
215 | compileItem.addActionListener(new ActionListener() {
216 | public void actionPerformed(ActionEvent e) {
217 | compile();
218 | }
219 | });
220 |
221 | runItem.addActionListener(new ActionListener() {
222 | public void actionPerformed(ActionEvent e) {
223 | if (success) {
224 | //该函数还没有做好
225 | run();
226 | }
227 | }
228 | });
229 | }
230 |
231 | //运行Pcode,目前不知道怎么传递输入,尤其是输入写在循环中时。
232 | private void run() {
233 | gsa.interpreter();
234 | /********
235 | List input = new ArrayList();
236 | String s = errorMessage.getText();
237 | String[] sp = s.split("\n");
238 | for (int i = 2; i < sp.length; i++) {
239 | //System.out.println(sp[i]);
240 | input.add(Integer.parseInt(sp[i]));
241 | }
242 | output = gsa.interpreter(input);
243 | for (int i = 0; i < output.size(); i++) {
244 | consoleMessage += output.get(i);
245 | }
246 | errorMessage.setText(consoleMessage);
247 | consoleMessage = "";
248 | ************/
249 | }
250 |
251 | //编译
252 | private void compile() {
253 | if (file == null) {
254 | JOptionPane.showMessageDialog(null, "请先保存文件");
255 | newFile();
256 | }
257 | saveFile();
258 | gsa = new GSAnalysis(file);
259 | clean();
260 | if (success = gsa.compile()) {
261 | displayAllToken();
262 | displayAllSymbol();
263 | displayAllPcode();
264 | consoleMessage += "compile succeed!\n";
265 | //consoleMessage += "请输入" + readNum + "个数,每行一个\n";
266 | errorMessage.setText(consoleMessage);
267 | } else {
268 | displayErrorMessage();
269 | consoleMessage += "compile failed!";
270 | errorMessage.setText(consoleMessage);
271 | }
272 | }
273 |
274 | //编译前清理一些表格和字符串
275 | private void clean() {
276 | flushTable(tokenTable);
277 | flushTable(symbolTable);
278 | flushTable(pcodeTable);
279 | errorMessage.setText("");
280 | consoleMessage = "";
281 | success = false;
282 | }
283 |
284 | private void displayErrorMessage() {
285 | consoleMessage = "";
286 | errors = gsa.getErrorMessage();
287 | for (int i = 0; i < errors.size(); i++) {
288 | consoleMessage += errors.get(i) + "\n";
289 | }
290 | }
291 |
292 | private void displayAllToken() {
293 | DefaultTableModel model = (DefaultTableModel)tokenTable.getModel();
294 | allToken = gsa.getAllToken();
295 | for (int i = 0; i < allToken.size(); i++) {
296 | Token token = allToken.get(i);
297 | Object[] rowValues = {token.getSt(), token.getLine(), token.getValue()};
298 | model.addRow(rowValues);
299 | }
300 | }
301 |
302 | private void displayAllSymbol() {
303 | DefaultTableModel model = (DefaultTableModel)symbolTable.getModel();
304 | allSymbol = gsa.getAllSymbol();
305 | for (int i = 0; i < allSymbol.size(); i++) {
306 | PerSymbol symbol = allSymbol.get(i);
307 | Object[] rowValues = {symbol.getName(), symbol.getType(), symbol.getValue(), symbol.getLevel(), symbol.getAddress()};
308 | model.addRow(rowValues);
309 | }
310 | }
311 |
312 | private void displayAllPcode() {
313 | DefaultTableModel model = (DefaultTableModel)pcodeTable.getModel();
314 | allPcode = gsa.getAllPcode();
315 | readNum = 0;
316 | for (int i = 0; i < allPcode.size(); i++) {
317 | PerPcode pcode = allPcode.get(i);
318 | if (pcode.getF() == Operator.OPR && pcode.getA() == 16) {
319 | readNum++;
320 | }
321 | Object[] rowValues = {pcode.getF(), pcode.getL(), pcode.getA()};
322 | model.addRow(rowValues);
323 | }
324 | }
325 |
326 | private void flushTable(JTable table) {
327 | ((DefaultTableModel) table.getModel()).getDataVector().clear(); //清除表格数据
328 | ((DefaultTableModel) table.getModel()).fireTableDataChanged();//通知模型更新
329 | table.updateUI();//刷新表格
330 | }
331 |
332 | //新建一个文件
333 | private void newFile() {
334 | if (file == null) {
335 | save.setVisible(true);
336 | String dirPath = save.getDirectory();
337 | String fileName = save.getFile();
338 | if(dirPath == null || fileName == null) {
339 | return;
340 | }
341 | file = new File(dirPath, fileName);
342 | }
343 | }
344 |
345 | //保存文件
346 | private void saveFile() {
347 | try {
348 | BufferedWriter bw = new BufferedWriter(new FileWriter(file));
349 | String text = jTextArea.getText();
350 | bw.write(text);
351 | bw.close();
352 | } catch (IOException ex) {
353 | throw new RuntimeException();
354 | }
355 | }
356 |
357 | public static void main(String[] args) {
358 | new MyCompiler();
359 | }
360 | }
361 |
--------------------------------------------------------------------------------
/src/Operator.java:
--------------------------------------------------------------------------------
1 | /**
2 | *created by shiyi in 2016/12/13
3 | *这是Pcode的伪操作符集合
4 | */
5 | public enum Operator {
6 | INT, CAL, LIT, LOD, STO, JMP, JPC, OPR;
7 | }
8 |
--------------------------------------------------------------------------------
/src/PerPcode.java:
--------------------------------------------------------------------------------
1 | /**
2 | * created by shiyi on 2016/12/14
3 | * 单句Pcode语句类
4 | */
5 | public class PerPcode {
6 | private Operator F;
7 | private int L;
8 | private int A;
9 |
10 | PerPcode(Operator _F, int _L, int _A) {
11 | F = _F;
12 | L = _L;
13 | A = _A;
14 | }
15 |
16 | public void setF(Operator _F) {
17 | F = _F;
18 | }
19 |
20 | public void setL(int _L) {
21 | L = _L;
22 | }
23 |
24 | public void setA(int _A) {
25 | A = _A;
26 | }
27 |
28 | public Operator getF() {
29 | return F;
30 | }
31 |
32 | public int getL() {
33 | return L;
34 | }
35 |
36 | public int getA() {
37 | return A;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/PerSymbol.java:
--------------------------------------------------------------------------------
1 | /**
2 | * created by shiyi on 2016/12/14
3 | * PerSymbol类
4 | */
5 | public class PerSymbol {
6 | private int type; //表示常量、变量或过程
7 | private int value; //表示常量或变量的值
8 | private int level; //嵌套层次
9 | private int address; //相对于所在嵌套过程基地址的地址
10 | private int size; //表示常量,变量,过程所占的大小(这一项其实默认为0, 并没有用到)
11 | private String name; //变量、常量或过程名
12 |
13 | public PerSymbol(int _type, int _value, int _level, int _address, int _size, String _name) {
14 | type = _type;
15 | value = _value;
16 | level = _level;
17 | address = _address;
18 | size = _size;
19 | name = _name;
20 | }
21 |
22 | public PerSymbol(int _type, int _level, int _address, int _size, String _name) {
23 | //专为变量声明和过程声明写的构造函数
24 | //变量和过程声明时没有初始值
25 | type = _type;
26 | level = _level;
27 | address = _address;
28 | size = _size;
29 | name = _name;
30 | }
31 |
32 | public void setType(int _type) {
33 | type = _type;
34 | }
35 |
36 | public void setValue(int _value) {
37 | value = _value;
38 | }
39 |
40 | public void setLevel(int _level) {
41 | level = _level;
42 | }
43 |
44 | public void setAddress(int _address) {
45 | address = _address;
46 | }
47 |
48 | public void setSize(int _size) {
49 | size = _size;
50 | }
51 |
52 | public void setName(String _name) {
53 | name = _name;
54 | }
55 |
56 | public int getType() {
57 | return type;
58 | }
59 |
60 | public int getValue() {
61 | return value;
62 | }
63 |
64 | public int getLevel() {
65 | return level;
66 | }
67 |
68 | public int getAddress() {
69 | return address;
70 | }
71 |
72 | public int getSize() {
73 | return size;
74 | }
75 |
76 | public String getName() {
77 | return name;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/SymType.java:
--------------------------------------------------------------------------------
1 | /**
2 | *created by shiyi on 2016/12/13
3 | *token类型
4 | */
5 | public enum SymType {
6 | BEG, END, IF, THEN, ELS, CON, PROC, VAR, DO, WHI, CAL, REA, WRI, ODD, REP, UNT,
7 | //begin, end, if, then, else, const, procedure, var, do, while, call, read, write, odd, repeat, until
8 | EQU, LES, LESE, LARE, LAR, NEQE, ADD, SUB, MUL, DIV,
9 | //=, <, <=, >=, >, <>, +, -, *, /
10 | SYM, CONST,
11 | //标识符, 常量
12 | CEQU, COMMA, SEMIC, POI, LBR, RBR,
13 | //:=, ',' , ';', '.', '(', ')'
14 | COL,
15 | //:
16 | EOF;
17 | //end of file
18 | }
19 |
--------------------------------------------------------------------------------
/src/Token.java:
--------------------------------------------------------------------------------
1 | /**
2 | *created by shiyi on 2016/12/14
3 | *token类
4 | */
5 | public class Token {
6 | private SymType st; //token的类别
7 | private int line; //token所在行,错误处理使用
8 | private String value; //token的值,只有标识符和常量有值
9 |
10 | public Token(SymType _st, int _line, String _value) {
11 | st = _st;
12 | line = _line;
13 | value = _value;
14 | }
15 |
16 | public void setSt(SymType _st) {
17 | st = _st;
18 | }
19 |
20 | public void setLine(int _line) {
21 | line = _line;
22 | }
23 |
24 | public void setValue(String _value) {
25 | value = _value;
26 | }
27 |
28 | public SymType getSt() {
29 | return st;
30 | }
31 |
32 | public int getLine() {
33 | return line;
34 | }
35 |
36 | public String getValue() {
37 | return value;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/testPL0/demo1.txt:
--------------------------------------------------------------------------------
1 | const z = 0;
2 | var head, foot, cock, rabbit, n;
3 | begin
4 | n := z;
5 | read(head, foot)
6 | ;
7 | cock := 1;
8 | while cock <= head do
9 | begin
10 | rabbit := head - cock;
11 | if cock * 2 + rabbit * 4 = foot then
12 | begin
13 | write(cock, rabbit);
14 | n := n + 1
15 | end;
16 | cock := cock + 1
17 | end;
18 | if n = 0 then write(0, 0)
19 | end.
20 |
--------------------------------------------------------------------------------
/testPL0/demo2.txt:
--------------------------------------------------------------------------------
1 | const a = 45, b = 27;
2 | var x, y, g, m;
3 | procedure swap;
4 | var temp;
5 | begin
6 | temp := x;
7 | x := y;
8 | y := temp
9 | end;
10 | procedure mod;
11 | x := x - x / y * y;
12 | begin
13 | x := a;
14 | y := b;
15 | call mod;
16 | while x <> 0 do
17 | begin
18 | call swap;
19 | call mod
20 | end;
21 | g := y;
22 | m := a * b / g;
23 | write(g, m)
24 | end.
25 |
--------------------------------------------------------------------------------
/testPL0/demo3.txt:
--------------------------------------------------------------------------------
1 | const true = 1, false = 0;
2 | var x, y, m, n, pf;
3 | procedure prime;
4 | var i, f;
5 | procedure mod;
6 | x := x - x / y * y;
7 | begin
8 | f := true;
9 | i := 3;
10 | while i < m do
11 | begin
12 | x := m;
13 | y := i;
14 | call mod;
15 | if x = 0 then f := false;
16 | i := i + 2
17 | end;
18 | if f = true then
19 | begin
20 | write(m);
21 | pf := true
22 | end
23 | end;
24 | begin
25 | pf := false;
26 | read(n);
27 | while n >= 2 do
28 | begin
29 | write(2);
30 | if n = 2 then pf := true;
31 | m := 3;
32 | while m <= n do
33 | begin
34 | call prime;
35 | m := m + 2
36 | end;
37 | read(n)
38 | end;
39 | if pf = false then write(0)
40 | end.
41 |
42 |
--------------------------------------------------------------------------------
/testPL0/demo4.txt:
--------------------------------------------------------------------------------
1 | const c1=1,c2=2;
2 | var v1,v2;
3 | begin
4 | read(v1,v2)
5 | v1:=v1+c1
6 | v2:=v2+c2
7 | write(v1,v2)
8 | end.
9 | const e = 1;
10 |
11 |
--------------------------------------------------------------------------------
/testPL0/demo5.txt:
--------------------------------------------------------------------------------
1 | const c1=1,c2=2;
2 | var v1,v2;
3 | begin
4 | read(v1,v2);
5 | v1:=v1+c1;
6 | v3:=v2+c2;
7 | write(v1,v2)
8 | end.
9 |
10 |
11 |
--------------------------------------------------------------------------------