├── .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 | ![运行界面](http://upload-images.jianshu.io/upload_images/3310089-b58a7a2bc69408fb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | --------------------------------------------------------------------------------