├── .gitignore ├── README.md └── src ├── Compiler.java ├── Converter.java ├── FileReader.java ├── GrammarParser.java ├── LexParser.java ├── Visitor.java ├── ast ├── BranchNode.java ├── LeafNode.java └── Node.java ├── component ├── .DS_Store ├── ERRORTYPE.java ├── GUNIT.java ├── Label.java ├── LineContainer.java ├── SYMBOL.java ├── Token.java ├── datatype │ ├── ArrayType.java │ ├── Datatype.java │ ├── IntType.java │ └── VoidType.java ├── graph │ ├── Graph.java │ └── Node.java └── narray │ ├── ConstNArray.java │ ├── NArray.java │ ├── NArrayItem.java │ ├── NInt.java │ └── NPos.java ├── exceptions ├── DuplicatedDefineException.java └── GramParseException.java ├── global ├── Config.java ├── Error.java └── Logger.java ├── imcode ├── .DS_Store ├── imexp │ ├── .DS_Store │ ├── AddExp.java │ ├── AssignByGetInt.java │ ├── AssignByRetExp.java │ ├── AssignByVarAddrExp.java │ ├── AssignByVarExp.java │ ├── AssignFromAddrExp.java │ ├── AssignToAddrExp.java │ ├── BeqExp.java │ ├── BgeExp.java │ ├── BgtExp.java │ ├── BneExp.java │ ├── CallExp.java │ ├── ConJumpExp.java │ ├── ConNotJumpExp.java │ ├── DivExp.java │ ├── IMExp.java │ ├── IMExpType.java │ ├── IMFac.java │ ├── JumpExp.java │ ├── LabelExp.java │ ├── ModExp.java │ ├── MulExp.java │ ├── OPTBranchExp.java │ ├── ParaDefExp.java │ ├── PrintStrExp.java │ ├── PrintVarExp.java │ ├── PushParaExp.java │ ├── ReturnExp.java │ └── SubExp.java └── imitem │ ├── FuncItem.java │ ├── IMItem.java │ ├── IMItemFac.java │ ├── IMItemType.java │ ├── IntItem.java │ ├── LabelItem.java │ ├── PosItem.java │ ├── SpaceItem.java │ ├── StrItem.java │ └── VarItem.java ├── improve └── component │ ├── BasicBlock.java │ ├── FlowGraph.java │ ├── ValidExp.java │ ├── optimizers │ ├── ConstOptimizer.java │ ├── GlobalExpOptimizer.java │ ├── Optimizer.java │ └── SeekOptimizer.java │ └── regpool │ ├── GlbRegPool.java │ ├── LocRegPool.java │ └── RegPool.java ├── mips ├── exps │ ├── MIPSExp.java │ ├── MIType.java │ └── MRType.java └── register │ └── Register.java ├── symbolstruct ├── CodeRegion.java ├── CodeText.java ├── Frame.java ├── FuncRegion.java ├── GlobalRegion.java ├── Region.java ├── Scope.java ├── Symer.java └── entries │ ├── AbsVarEntry.java │ ├── ArrayEntry.java │ ├── ConstArrayEntry.java │ ├── ConstFeature.java │ ├── ConstValueEntry.java │ ├── ConstVarEntry.java │ ├── Entry.java │ ├── FuncEntry.java │ ├── SpaceEntry.java │ └── VarEntry.java └── symboltable ├── BasicType.java ├── Block.java ├── BlockType.java ├── SymbolItemType.java ├── SymbolTable.java └── symbols ├── ArraySymbolItem.java ├── FuncSymbolItem.java ├── StrSymbolItem.java ├── SymbolItem.java └── VarSymbolItem.java /.gitignore: -------------------------------------------------------------------------------- 1 | /out/ 2 | *.zip 3 | *.txt 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | 这是北航编译原理课程的课设分享 4 | 5 | 如果是不打算采取SSA的同学可以参考本人的设计 6 | 7 | 该编译器性能与采用了SSA的同学性能不相上下甚至略高 8 | 9 | 采用了直接且暴力的手段进行了性能优化 10 | 11 | # 中间代码翻译阶段问题汇总 12 | 13 | - 函数如何调用?如何传回返回值? 14 | 1. 函数调用前,先将参数依次放入当前栈帧,然后跳转到函数开头位置。 15 | 2. 为被调用函数过程创建新的栈帧,存储所有调用者的S寄存器及$ra寄存器,保存现场。 16 | 3. 被调用函数执行自己的功能。 17 | 4. 被调用函数完成自己的功能。 18 | 5. 被调用函数清除自己的栈帧,并且清除调用者传入的参数栈,恢复调用者现场,将结果放在寄存器中返回。 19 | 6. 一个函数的栈帧通常存储的都是该函数声明的变量 20 | 7. 函数调用的参数传递用不用专用寄存器$a1、$a2、$a3、$a4? 21 | 8. 保存和恢复现场的时候是否只需要保存和恢复该函数所用到的寄存器即可?如何在进入函数前就预测到? 22 | - 显然不能预知,等优化吧(笑 23 | - 数组变量如何处理?一维数组,二维数组…… 24 | - 对于变量类型匹配,只考虑维度 25 | - 对于数组类型,其存储的值为其初始化时的首地址、维度信息、名称 26 | - 数组变量初始化声明时,在当前栈中申请对应长度的空间 27 | - 初始化和赋值不完全相同,初始化时支持用数组赋值,赋值时仅支持Exp。因此在初始化时考虑数组整体赋值,而在赋值时仅考虑用Exp进行数组元素的赋值。 28 | - 在赋值语句中,将多维数组看作一维数组处理,这意味着操作数分别为数组对象和其一维化后的偏移总量 29 | - 将数组传入函数时,传递的实际是其首地址。 30 | - 对数组对象进行操作时,可以发现我们均仅需其首地址即可。 31 | - printf如何处理? 32 | - printf中传入的字符串可以以%d为分割符,将其分为多段,每一段均存储在静态变量区。当调用printf语句时,分别间隔答应每一段,并在其中穿插输出参数值。 33 | - getint()如何处理? 34 | - 提前将getint()函数的实现放在开头,然后将其当作普通函数处理 35 | - 在从中间代码向汇编代码生成时,比如Add a b c,如何把a、b、c替换为合适的寄存器? 36 | - 记录一个类似符号表的栈帧记录器,其中记录了当前作用域下每个变量的存储地址 37 | - 记录一个全局的变量-寄存器字典和一个局部的变量-寄存器字典 38 | - 对变量a,先在全局找a,如果找到a对应寄存器,就用;如果没找到,则从栈帧记录器中提取出变量地址后,申请一个寄存器存放。 39 | 40 | ## 数组的若干问题 41 | 42 | 1. 程序中的数组是什么? 43 | - 是符号项的类型,符号项的类型就是变量的类型 44 | - 操作集合:判断类型是否一致,甄别不同四元组操作 45 | - ArrayType是DataType的子类 46 | - ArrayType需要指明基本类型和维度情况 47 | - 一个数组的符号项有以下特点: 48 | - pos:指向的空间只有一个整型大小,该位置存储一个指向数组实际空间的值。 49 | - 注意pos指向的是该变量存储的位置,而其值指向的是该数组实际存储的位置。 50 | - 实际上和普通符号项VarEntry基本结构一致,只是存储的值从语义上有区别 51 | - 是物理存储结构,即数组如何在汇编程序中存储 52 | - 操作集合:全局初始化赋值,全局赋值,局部赋值,局部取值,全局取值 53 | - NArray承担的角色是,将程序AST中的语法元素解析为接近物理存储结构的数组对象的中介类型 54 | - NArray包含一个ArrayType对象用于指示其维度类型 55 | - NArray中以线性方式存储一个空间 56 | - 全局初始化赋值时,先按照初始化值生成一个NArray对象,然后将该NArray对象映射到栈中指定位置(语法中只允许在初始化时使用数组赋值),然后生成一个数组符号项,将其值设置为该空间的起始地址。NArray的元素存在以下情况,要么是常数,要么是变量表达式 57 | - 局部赋值时,数组对象不能作为左值,因此左值一定是数组的最底层元素,即基本类型的普通变量,使用的value值一定也是普通变量或常数(实际转变为临时变量)。用一个四元式能够将指定变量赋值给数组中指定位置的元素。VarEntry -> ArrayEntry[Pos] 58 | - 局部取值时,按照读取时的指示变量,创建一个新的符号项tmp并返回。注意数组对象局部取值时生成的tmp对象,做一个局部变量处理,即完整地进行变量声明、变量初始化。如果取值得到的是基本元素,那么得到的变量是一个普通变量,其pos,其值即为其真正值,是从原数组空间复制过来的;如果取值得到的是一个数组变量,其值为数组的对应物理起始地址。这里需要一个四元式能够完成从数组中取出一个数组变量,一个四元式能够从数组中取出一个普通变量。AbsVarEntry <- ArrayEntry[Pos] 59 | - 数组对象传递时,直接传递符号项。对于局部取值传递,传递的符号项是tmp变量 60 | - 全局取值时,直接返回当前符号项 61 | 2. 数组的物理存储结构: 62 | - 初始化定义时分配空间 63 | - 符号项中存储的值是其起始位置 64 | 65 | ## 函数调用 66 | 67 | 1. 函数的定义一定在全局块中 68 | 69 | 2. 函数如何调用? 70 | 71 | - 直接跳转:jump后从v寄存器取出值 72 | 73 | 3. 函数如何传值? 74 | 75 | - 先push参数,将其按次序放进栈中 76 | - 然后Call函数跳转到函数内部 77 | - 函数内部首先需要Def所有参数,即在符号表中建立对应变量并在栈中申请空间,然后通过传入的实参完成赋值。 78 | 79 | 4. 函数如何返回值? 80 | 81 | - 返回值一定是VarEntry 82 | 83 | - 将VarEntry赋值到v寄存器 84 | 85 | ## 翻译中间代码时 86 | 87 | 每进入一个函数Scope,则将通过移动$sp将所有需要的局部变量的空间alloc出来 88 | 89 | - 所有变量,包括数组空间和中间变量空间 90 | - 之后的一切操作,均从内存中获取变量。寄存器仅在单个语句范围中使用。 91 | - 对于每个Scope记录其局部变量名称到其偏移的映射关系。 92 | - 对于每个局部变量,其同时需要记录名称和其对应的Scope名称 93 | 94 | 移动sp后,还需要将指定的数组符号项进行赋值,即将数组符号项的内容赋值为申请的空间的地址。 95 | 96 | 函数定义时,在解析参数时,将参数放入当前函数的Scope符号表时,注意其处在\$ra之前,\$ra之后才是函数内部的其他局部变量和临时变量。 97 | 98 | 函数传递参数时,通过push方式向当前栈指针$sp的下方压入值(而不改变\$sp)。跳转后,由函数自己扩展栈。 99 | 100 | 一个函数的栈如何管理? 101 | 102 | - 在进行FuncDef时,记录所有该函数内的Scope中的符号表项,并且加上函数参数列表中的符号表项,形成属于这个Func的栈帧对象。 103 | - 在生成目标代码时,统一通过Func的栈帧对象初始化栈帧空间。 104 | - 当进入某个Scope后,我们遇到一个变量a,首先查Scope表,找到a的对应符号表项ae,然后用ae去当前栈帧空间内找到对应地址。 105 | - 栈帧对象需要记录符号表项到偏移的映射,因此上一步中,我们进一步获得了a相对于栈帧的偏移量。 106 | - 栈帧在初始化后,\$sp就是指着该栈帧的最底部,因此可以通过偏移+\$sp来获得a的实际地址 107 | 108 | 使用FuncRegion来同时描述当前函数的栈帧和相对于的所有中间代码。每个FuncRegion无法相互访问,然而同时共享一个全局变量声明块。 109 | 110 | 全局变量的声明有异于其他所有变量,其不从属于任何FuncRegion,而是由全局所共用。 111 | 112 | 当任意语句访问到某个变量声明时,首先检查其是否是全局变量,如果是,则从全局块进行加载;否则,则从该语句所属的FuncRegion的Frame对象加载。 113 | 114 | 判断一个变量是否是全局变量的依据是其符号表项所属的Scope的level = 0 115 | 116 | ## 运行时栈和寄存器管理 117 | 118 | 生成目标代码时,我们需要将中间代码翻译为实际目标代码。 119 | 120 | 当我们遇到一个未分配寄存器的变量时,我们从空闲寄存器中向其分配一个寄存器,并记录下来(RegMap)。 121 | 122 | 如果此时没有空闲寄存器,则触发替换。假设我们随机选中一个寄存器R,其已经被分配给变量V,我们建立一个MemMap,然后将寄存器R的值存入栈中,然后将栈中地址和变量V放入MemMap中,然后将寄存器R空出来。如果我们后续又访问到V中取值,则向其分配一个寄存器,然后根据MemMap将其取出。 123 | 124 | RegMap和MemMap都是针对一个栈帧而言的。每个栈帧维护着自己的两个Map。 125 | 126 | 一个栈帧对应一个{},即我们的Scope。注意以下情况: 127 | 128 | ```c 129 | int main() { 130 | int a = 10; 131 | int b = 10; 132 | { 133 | int a; 134 | a = 100; 135 | b = 100; 136 | } 137 | return 0; 138 | } 139 | ``` 140 | 141 | 上述在内层Scope中,存在两个a定义。实际上,我们区分两个变量是否是同一个,需要同时考虑其所属的Scope和其名称。 142 | 143 | 考虑上述代码分析过程,我们首先中外层scope定义了ab两个变量,然后进入内层后,再一次定义了a。在a=100时找到的是内层Scope的a而不是外层Scope的a。 144 | 145 | 当我们遇到一个已经被分配了寄存器的普通变量时,我们认为赋值和取值都是针对它进行。 146 | 147 | # 优化阶段工作 148 | 149 | 主要采用的优化方式为流图分析,其主要优化逻辑写在improve.component.FlowGraph中 150 | 151 | - 全局优化 152 | 153 | - 局部常量传播 154 | 155 | - 全局公共表达式消除 156 | 157 | - 全局复制传播 158 | 159 | - 窥孔优化 160 | 161 | - 条件跳转优化 162 | 163 | - 死代码优化 164 | 165 | - 立即赋值优化 166 | 167 | - 循环优化 168 | 169 | - 删除无效循环 170 | 171 | 目标代码生成时采用了图着色算法进行寄存器分配,其逻辑位于improve.component.regpool下,其对性能提升影响显著 172 | 173 | 目标代码生成关键在于除法优化,其优化逻辑位于imcode.imexp.DivExp,其对性能提升影响显著 174 | -------------------------------------------------------------------------------- /src/Compiler.java: -------------------------------------------------------------------------------- 1 | import ast.Node; 2 | import component.Token; 3 | import global.Config; 4 | import global.Logger; 5 | import symbolstruct.CodeRegion; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Compiler 入口主类 11 | */ 12 | public class Compiler { 13 | public static void main(String[] args) { 14 | LexParser lexParser = new LexParser(Config.inputFilePath); 15 | List tokenList = lexParser.parse(); 16 | tokenList.stream().forEach(token -> Logger.GetLogger().LexParserLog(token.getSymbol(), token.getValue())); 17 | GrammarParser gramParser = new GrammarParser(tokenList); 18 | Node astRoot = gramParser.parse(); 19 | // Visitor visitor = new Visitor(astRoot); 20 | // visitor.visit(); 21 | Converter converter = new Converter(astRoot); 22 | CodeRegion codeRegion = converter.visit(); 23 | Logger.GetLogger().DumpError(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/FileReader.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.io.FileInputStream; 3 | import java.io.InputStreamReader; 4 | import java.io.Reader; 5 | 6 | /** 7 | * FileReader是用于读取文件的类,其中封装了对于 文件指针的管理 和 字符类型的判断 8 | * 9 | * @author neumy 10 | * @version jdk1.8.0 11 | */ 12 | public class FileReader { 13 | private String inputFilePath; 14 | private StringBuffer token; 15 | private StringBuffer text; 16 | private Integer ptr; 17 | private Integer curLine; 18 | private Character curChar; 19 | 20 | /** 21 | * 初始化函数 22 | * 23 | * @param inputFilePath:源程序文件存储路径 24 | */ 25 | public FileReader(String inputFilePath) { 26 | this.inputFilePath = inputFilePath; 27 | 28 | this.text = new StringBuffer(); 29 | try { 30 | File file = new File(inputFilePath); 31 | Reader reader = new InputStreamReader(new FileInputStream(file)); 32 | int tempchar; 33 | while ((tempchar = reader.read()) != -1) { 34 | this.text.append((char) tempchar); 35 | } 36 | this.text.append((char) 0); 37 | reader.close(); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | this.text.append('\n'); 42 | this.text.append((char)0); 43 | this.ptr = 0; 44 | this.curLine = 1; 45 | this.token = new StringBuffer(); 46 | } 47 | 48 | /** 49 | * 将行号加一 50 | */ 51 | public void pushLine() { 52 | this.curLine++; 53 | } 54 | 55 | /** 56 | * 将行号后退一 57 | */ 58 | public void retractLine() { 59 | this.curLine--; 60 | if (this.curLine < 0) throw new RuntimeException("retract line unavailable"); 61 | } 62 | 63 | /** 64 | * 返回当前指针所在行 65 | * 66 | * @return 行号,用Integer表示 67 | */ 68 | public Integer getCurLine() { 69 | return curLine; 70 | } 71 | 72 | public void catToken() { 73 | this.token.append(this.text.charAt(ptr)); 74 | } 75 | 76 | public void clearToken() { 77 | this.token = new StringBuffer(); 78 | } 79 | 80 | public void getChar() { 81 | this.ptr++; 82 | this.curChar = this.text.charAt(this.ptr); 83 | } 84 | 85 | public void retract() { 86 | this.ptr--; 87 | if (this.ptr < 0) throw new RuntimeException("retract ptr unavailable"); 88 | } 89 | 90 | public StringBuffer getToken() { 91 | return this.token; 92 | } 93 | 94 | public StringBuffer getText() { 95 | return this.text; 96 | } 97 | 98 | /** 99 | * 当前ptr字符是否是空格 100 | * 101 | * @return 是或否 102 | */ 103 | public Boolean isSpace() { 104 | int temp = (int) this.text.charAt(ptr); 105 | return (temp <= 15 && temp >= 11) || temp == 32; 106 | } 107 | 108 | /** 109 | * 当前ptr字符是否是换行符\n或\r 110 | * 111 | * @return 是或否 112 | */ 113 | public Boolean isNewlineN() { 114 | return this.text.charAt(ptr) == '\n'; 115 | } 116 | 117 | /** 118 | * 当前ptr字符是否是换行符\r 119 | * 120 | * @return 是或否 121 | */ 122 | public Boolean isNewlineR() { 123 | return this.text.charAt(ptr) == '\r'; 124 | } 125 | 126 | /** 127 | * 当前ptr字符是否是Tab 128 | * 129 | * @return 是或否 130 | */ 131 | public Boolean isTab() { 132 | return this.text.charAt(ptr) == '\t'; 133 | } 134 | 135 | /** 136 | * 当前ptr字符是否是字母 137 | * 138 | * @return 是或否 139 | */ 140 | public Boolean isLetter() { 141 | return (this.text.charAt(ptr) >= 'a' && this.text.charAt(ptr) <= 'z') 142 | || (this.text.charAt(ptr) >= 'A' && (this.text.charAt(ptr) <= 'Z')) 143 | || this.text.charAt(ptr) == '_'; 144 | } 145 | 146 | /** 147 | * 当前ptr字符是否是数字0~9 148 | * 149 | * @return 是或否 150 | */ 151 | public Boolean isDigit() { 152 | return this.text.charAt(ptr) >= '0' && this.text.charAt(ptr) <= '9'; 153 | } 154 | 155 | /** 156 | * 当前ptr字符是否是非零数字 157 | * 158 | * @return 是或否 159 | */ 160 | public Boolean isNZeroDigit() { 161 | return this.text.charAt(ptr) >= '1' && this.text.charAt(ptr) <= '9'; 162 | } 163 | 164 | /** 165 | * 当前ptr字符是否是逗号 166 | * 167 | * @return 是或否 168 | */ 169 | public Boolean isComma() { 170 | return this.text.charAt(ptr) == ','; 171 | } 172 | 173 | /** 174 | * 当前ptr字符是否是分号 175 | * 176 | * @return 是或否 177 | */ 178 | public Boolean isSemi() { 179 | return this.text.charAt(ptr) == ';'; 180 | } 181 | 182 | /** 183 | * 当前ptr字符是否是等号 184 | * 185 | * @return 是或否 186 | */ 187 | public Boolean isEqu() { 188 | return this.text.charAt(ptr) == '='; 189 | } 190 | 191 | /** 192 | * 当前ptr字符是否是加号 193 | * 194 | * @return 是或否 195 | */ 196 | public Boolean isPlus() { 197 | return this.text.charAt(ptr) == '+'; 198 | } 199 | 200 | /** 201 | * 当前ptr字符是否是减号 202 | * 203 | * @return 是或否 204 | */ 205 | public Boolean isMinus() { 206 | return this.text.charAt(ptr) == '-'; 207 | } 208 | 209 | /** 210 | * 当前ptr字符是否是除号 211 | * 212 | * @return 是或否 213 | */ 214 | public Boolean isDiv() { 215 | return this.text.charAt(ptr) == '/'; 216 | } 217 | 218 | /** 219 | * 当前ptr字符是否是乘号 220 | * 221 | * @return 是或否 222 | */ 223 | public Boolean isMulti() { 224 | return this.text.charAt(ptr) == '*'; 225 | } 226 | 227 | /** 228 | * 当前ptr字符是否是求模符号 229 | * 230 | * @return 是或否 231 | */ 232 | public Boolean isMod() { 233 | return this.text.charAt(ptr) == '%'; 234 | } 235 | 236 | /** 237 | * 当前ptr字符是否是& 238 | * 239 | * @return 是或否 240 | */ 241 | public Boolean isAnd() { 242 | return this.text.charAt(ptr) == '&'; 243 | } 244 | 245 | /** 246 | * 当前ptr字符是否是| 247 | * 248 | * @return 是或否 249 | */ 250 | public Boolean isOr() { 251 | return this.text.charAt(ptr) == '|'; 252 | } 253 | 254 | /** 255 | * 当前ptr字符是否是小于号 256 | * 257 | * @return 是或否 258 | */ 259 | public Boolean isLss() { 260 | return this.text.charAt(ptr) == '<'; 261 | } 262 | 263 | /** 264 | * 当前ptr字符是否是大于号 265 | * 266 | * @return 是或否 267 | */ 268 | public Boolean isGre() { 269 | return this.text.charAt(ptr) == '>'; 270 | } 271 | 272 | /** 273 | * 当前ptr字符是否是感叹号 274 | * 275 | * @return 是或否 276 | */ 277 | public Boolean isExclamation() { 278 | return this.text.charAt(ptr) == '!'; 279 | } 280 | 281 | /** 282 | * 当前ptr字符是否是左括号 283 | * 284 | * @return 是或否 285 | */ 286 | public Boolean isLeftParent() { 287 | return this.text.charAt(ptr) == '('; 288 | } 289 | 290 | /** 291 | * 当前ptr字符是否是右括号 292 | * 293 | * @return 是或否 294 | */ 295 | public Boolean isRightParent() { 296 | return this.text.charAt(ptr) == ')'; 297 | } 298 | 299 | /** 300 | * 当前ptr字符是否是左中括号 301 | * 302 | * @return 是或否 303 | */ 304 | public Boolean isLeftBracket() { 305 | return this.text.charAt(ptr) == '['; 306 | } 307 | 308 | /** 309 | * 当前ptr字符是否是右中括号 310 | * 311 | * @return 是或否 312 | */ 313 | public Boolean isRightBracket() { 314 | return this.text.charAt(ptr) == ']'; 315 | } 316 | 317 | /** 318 | * 当前ptr字符是否是左大括号 319 | * 320 | * @return 是或否 321 | */ 322 | public Boolean isLeftBrace() { 323 | return this.text.charAt(ptr) == '{'; 324 | } 325 | 326 | /** 327 | * 当前ptr字符是否是右大括号 328 | * 329 | * @return 是或否 330 | */ 331 | public Boolean isRightBrace() { 332 | return this.text.charAt(ptr) == '}'; 333 | } 334 | 335 | /** 336 | * 当前ptr字符是否是反斜杠 337 | * 338 | * @return 是或否 339 | */ 340 | public Boolean isEscape() { 341 | return this.text.charAt(ptr) == '\\'; 342 | } 343 | 344 | /** 345 | * 当前ptr字符是否是单引号 346 | * 347 | * @return 是或否 348 | */ 349 | public Boolean isSinQuotation() { 350 | return this.text.charAt(ptr) == '\''; 351 | } 352 | 353 | /** 354 | * 当前ptr字符是否是双引号 355 | * 356 | * @return 是或否 357 | */ 358 | public Boolean isDouQuotation() { 359 | return this.text.charAt(ptr) == '\"'; 360 | } 361 | 362 | /** 363 | * 当前ptr字符是否是结束符号 364 | * 365 | * @return 是或否 366 | */ 367 | public Boolean isEOT() { 368 | return (int) this.text.charAt(ptr) == 0; 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /src/LexParser.java: -------------------------------------------------------------------------------- 1 | import component.SYMBOL; 2 | import component.Token; 3 | import global.Error; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * LexParser 词法分析器 10 | * 其parse方法返回一个Token List 11 | * 12 | * @author neumy 13 | * @version jdk1.8.0 14 | */ 15 | public class LexParser { 16 | private final FileReader reader; 17 | private final List tokenList; 18 | 19 | public LexParser(String inputFilePath) { 20 | this.reader = new FileReader(inputFilePath); 21 | this.tokenList = new ArrayList<>(); 22 | } 23 | 24 | public List parse() { 25 | while (true) { 26 | SYMBOL symbol = SYMBOL.IGNORE; 27 | reader.clearToken(); 28 | /* 清除无关空白符 */ 29 | while (reader.isSpace() || reader.isNewlineN() || reader.isNewlineR() || reader.isTab()) { 30 | // 假设仅计 \n 31 | if (reader.isNewlineN()) { 32 | reader.pushLine(); 33 | } 34 | reader.getChar(); 35 | } 36 | 37 | /* 枚举优先级:保留字 - 标识符 - 常整数 - 分界符 - 字符串 */ 38 | /* 保留字与标识符 */ 39 | if (reader.isLetter()) { 40 | while (reader.isLetter() || reader.isDigit()) { 41 | reader.catToken(); 42 | reader.getChar(); 43 | } 44 | reader.retract(); 45 | SYMBOL resultValue = reserve(reader.getToken().toString()); 46 | if (resultValue == SYMBOL.UNKNOWN) 47 | symbol = SYMBOL.IDENFR; 48 | else 49 | symbol = resultValue; 50 | } 51 | /* 常整数, 不允许前置零 */ 52 | else if (reader.isDigit()) { 53 | // 非零整数 54 | if (reader.isNZeroDigit()) { 55 | while (reader.isDigit()) { 56 | reader.catToken(); 57 | reader.getChar(); 58 | } 59 | reader.retract(); 60 | symbol = SYMBOL.INTCON; 61 | } 62 | // 零 63 | else { 64 | reader.catToken(); 65 | reader.getChar(); 66 | if (!reader.isDigit()) { 67 | reader.retract(); 68 | symbol = SYMBOL.INTCON; 69 | } else 70 | Error.lexError(reader.getCurLine(), SYMBOL.INTCON); 71 | } 72 | } 73 | /* 双分界符 */ 74 | else if (reader.isLss()) { 75 | // < <= 76 | reader.catToken(); 77 | reader.getChar(); 78 | if (reader.isEqu()) { 79 | reader.catToken(); 80 | symbol = SYMBOL.LEQ; 81 | } else { 82 | reader.retract(); 83 | symbol = SYMBOL.LSS; 84 | } 85 | } else if (reader.isGre()) { 86 | // > >= 87 | reader.catToken(); 88 | reader.getChar(); 89 | if (reader.isEqu()) { 90 | reader.catToken(); 91 | symbol = SYMBOL.GEQ; 92 | } else { 93 | reader.retract(); 94 | symbol = SYMBOL.GRE; 95 | } 96 | } else if (reader.isEqu()) { 97 | // = == 98 | reader.catToken(); 99 | reader.getChar(); 100 | if (reader.isEqu()) { 101 | reader.catToken(); 102 | symbol = SYMBOL.EQL; 103 | } else { 104 | reader.retract(); 105 | symbol = SYMBOL.ASSIGN; 106 | } 107 | } else if (reader.isExclamation()) { 108 | // ! != 109 | reader.catToken(); 110 | reader.getChar(); 111 | if (reader.isEqu()) { 112 | reader.catToken(); 113 | symbol = SYMBOL.NEQ; 114 | } else { 115 | reader.retract(); 116 | symbol = SYMBOL.NOT; 117 | } 118 | } else if (reader.isAnd()) { 119 | // && 120 | reader.catToken(); 121 | reader.getChar(); 122 | if (reader.isAnd()) { 123 | reader.catToken(); 124 | symbol = SYMBOL.AND; 125 | } else { 126 | Error.lexError(reader.getCurLine(), SYMBOL.UNKNOWN); 127 | } 128 | } else if (reader.isOr()) { 129 | // for || 130 | reader.catToken(); 131 | reader.getChar(); 132 | if (reader.isOr()) { 133 | reader.catToken(); 134 | symbol = SYMBOL.OR; 135 | } else { 136 | Error.lexError(reader.getCurLine(), SYMBOL.UNKNOWN); 137 | } 138 | } 139 | /* 单分界符号 */ 140 | else if (reader.isPlus()) { 141 | reader.catToken(); 142 | symbol = SYMBOL.PLUS; 143 | } else if (reader.isMinus()) { 144 | reader.catToken(); 145 | symbol = SYMBOL.MINU; 146 | } else if (reader.isMulti()) { 147 | reader.catToken(); 148 | symbol = SYMBOL.MULT; 149 | } else if (reader.isDiv()) { 150 | reader.catToken(); 151 | reader.getChar(); 152 | // 进入单行注释 153 | if (reader.isDiv()) { 154 | // 仅计 \n 155 | while (!reader.isNewlineN()) { 156 | reader.getChar(); 157 | } 158 | reader.pushLine(); // 进行换行处理 159 | symbol = SYMBOL.IGNORE; 160 | } 161 | // 进入多行注释 162 | else if (reader.isMulti()) { 163 | reader.getChar(); 164 | while (true) { 165 | while (!reader.isMulti()) { 166 | // 仅计 \n 167 | if (reader.isNewlineN()) { 168 | reader.pushLine(); 169 | } 170 | reader.getChar(); 171 | } 172 | reader.getChar(); 173 | if (reader.isDiv()) { 174 | break; 175 | } else { 176 | continue; 177 | } 178 | } 179 | symbol = SYMBOL.IGNORE; 180 | // 多行注释的最后一个换行符留到了下一次循环进行处理 181 | } else { 182 | reader.retract(); 183 | symbol = SYMBOL.DIV; 184 | } 185 | } else if (reader.isMod()) { 186 | reader.catToken(); 187 | symbol = SYMBOL.MOD; 188 | } else if (reader.isSemi()) { 189 | reader.catToken(); 190 | symbol = SYMBOL.SEMICN; 191 | } else if (reader.isComma()) { 192 | reader.catToken(); 193 | symbol = SYMBOL.COMMA; 194 | } else if (reader.isLeftParent()) { 195 | reader.catToken(); 196 | symbol = SYMBOL.LPARENT; 197 | } else if (reader.isRightParent()) { 198 | reader.catToken(); 199 | symbol = SYMBOL.RPARENT; 200 | } else if (reader.isLeftBracket()) { 201 | reader.catToken(); 202 | symbol = SYMBOL.LBRACK; 203 | } else if (reader.isRightBracket()) { 204 | reader.catToken(); 205 | symbol = SYMBOL.RBRACK; 206 | } else if (reader.isLeftBrace()) { 207 | reader.catToken(); 208 | symbol = SYMBOL.LBRACE; 209 | } else if (reader.isRightBrace()) { 210 | reader.catToken(); 211 | symbol = SYMBOL.RBRACE; 212 | } 213 | /* 字符串 */ 214 | else if (reader.isDouQuotation()) { 215 | reader.catToken(); 216 | reader.getChar(); 217 | while (!reader.isDouQuotation()) { 218 | reader.catToken(); 219 | reader.getChar(); 220 | } 221 | if (reader.isDouQuotation()) { 222 | reader.catToken(); 223 | symbol = SYMBOL.STRCON; 224 | } else { 225 | Error.lexError(reader.getCurLine(), SYMBOL.STRCON); 226 | } 227 | } else if (reader.isEOT()) { 228 | break; 229 | } else { 230 | Error.lexError(reader.getCurLine(), SYMBOL.UNKNOWN); 231 | } 232 | 233 | if (symbol != SYMBOL.IGNORE) { 234 | this.tokenList.add(new Token(symbol, reader.getToken().toString(), reader.getCurLine())); 235 | } 236 | 237 | reader.getChar(); 238 | } 239 | return this.tokenList; 240 | } 241 | 242 | public SYMBOL reserve(String value) { 243 | if (value.equals("const")) return SYMBOL.CONSTTK; 244 | else if (value.equals("int")) return SYMBOL.INTTK; 245 | else if (value.equals("void")) return SYMBOL.VOIDTK; 246 | else if (value.equals("main")) return SYMBOL.MAINTK; 247 | else if (value.equals("if")) return SYMBOL.IFTK; 248 | else if (value.equals("else")) return SYMBOL.ELSETK; 249 | else if (value.equals("while")) return SYMBOL.WHILETK; 250 | else if (value.equals("printf")) return SYMBOL.PRINTFTK; 251 | else if (value.equals("return")) return SYMBOL.RETURNTK; 252 | else if (value.equals("break")) return SYMBOL.BREAKTK; 253 | else if (value.equals("continue")) return SYMBOL.CONTINUETK; 254 | else if (value.equals("getint")) return SYMBOL.GETINTTK; 255 | else return SYMBOL.UNKNOWN; 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /src/ast/BranchNode.java: -------------------------------------------------------------------------------- 1 | package ast; 2 | 3 | import component.GUNIT; 4 | import component.Token; 5 | 6 | import java.util.ArrayList; 7 | 8 | public class BranchNode implements Node { 9 | private ArrayList children; 10 | private Node parent; 11 | private Integer level; 12 | private GUNIT value; 13 | private Boolean correct; 14 | 15 | public BranchNode(GUNIT gunit) { 16 | this.children = new ArrayList<>(); 17 | this.level = -1; 18 | this.parent = null; 19 | this.value = gunit; 20 | this.correct = null; 21 | } 22 | 23 | @Override 24 | public void addChild(Node child) { 25 | this.children.add(child); 26 | child.setParent(this); 27 | } 28 | 29 | @Override 30 | public void setParent(Node parent) { 31 | this.parent = parent; 32 | this.level = parent.getLevel() + 1; 33 | } 34 | 35 | @Override 36 | public ArrayList getChildren() { 37 | return this.children; 38 | } 39 | 40 | @Override 41 | public Node getParent() { 42 | return this.parent; 43 | } 44 | 45 | public GUNIT getGUnit() { 46 | return value; 47 | } 48 | 49 | @Override 50 | public Boolean isCorrect() { 51 | return correct; 52 | } 53 | 54 | @Override 55 | public Integer getLevel() { 56 | return level; 57 | } 58 | 59 | public void setCorrect(Boolean correct) { 60 | this.correct = correct; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return value.toString(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/ast/LeafNode.java: -------------------------------------------------------------------------------- 1 | package ast; 2 | 3 | import component.SYMBOL; 4 | import component.Token; 5 | 6 | import java.util.ArrayList; 7 | 8 | public class LeafNode implements Node { 9 | private Node parent; 10 | private Integer level; 11 | private Token value; 12 | private SYMBOL type; 13 | private Boolean correct; 14 | 15 | public LeafNode(SYMBOL type, Token token, Boolean isCorrect) { 16 | this.parent = null; 17 | this.level = -1; 18 | this.value = token; 19 | this.correct = isCorrect; 20 | this.type = type; 21 | } 22 | 23 | @Override 24 | public void addChild(Node child) { 25 | System.err.println("IN LeafNode: Try to add child to a leaf node!"); 26 | } 27 | 28 | @Override 29 | public void setParent(Node parent) { 30 | this.parent = parent; 31 | this.level = parent.getLevel() + 1; 32 | } 33 | 34 | @Override 35 | public ArrayList getChildren() { 36 | System.err.println("IN LeafNode: Try to get child from a leaf node!"); 37 | return null; 38 | } 39 | 40 | @Override 41 | public Node getParent() { 42 | return this.parent; 43 | } 44 | 45 | public Token getToken() { 46 | return value; 47 | } 48 | 49 | @Override 50 | public Boolean isCorrect() { 51 | return correct; 52 | } 53 | 54 | @Override 55 | public Integer getLevel() { 56 | return level; 57 | } 58 | 59 | public SYMBOL getType() { 60 | return type; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return type.name() + " " + this.getToken().getValue(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/ast/Node.java: -------------------------------------------------------------------------------- 1 | package ast; 2 | 3 | import component.Token; 4 | 5 | import java.util.ArrayList; 6 | 7 | public interface Node { 8 | void addChild(Node child); 9 | void setParent(Node parent); 10 | ArrayList getChildren(); 11 | Node getParent(); 12 | Boolean isCorrect(); 13 | Integer getLevel(); 14 | } 15 | -------------------------------------------------------------------------------- /src/component/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neumyor/C_Complier_on_Java/2ce325a4abf677eee111281d8fddf122ab1a6491/src/component/.DS_Store -------------------------------------------------------------------------------- /src/component/ERRORTYPE.java: -------------------------------------------------------------------------------- 1 | package component; 2 | 3 | public enum ERRORTYPE { 4 | LexError, 5 | Redefine, 6 | Undefine, 7 | FuncParamNumUnmatch, 8 | FuncParamTypeUnmatch, 9 | ConditionError, 10 | VoidWithReturn, 11 | ReturnError, 12 | ArrayIndexWrong, 13 | ConstModify, 14 | MissSemicn, 15 | MissRightParent, 16 | MissRightBrack, 17 | MissWhile, 18 | ConstDefWrong 19 | } 20 | -------------------------------------------------------------------------------- /src/component/GUNIT.java: -------------------------------------------------------------------------------- 1 | package component; 2 | 3 | /** 4 | * component.GUNIT 语法分析的解析单元,对应文法中的所有非终结符 5 | *

6 | * 其中PureChar是用于检查多可能的终结符所特设的,比如乘除模运算符有三种。 7 | * 这种结构虽然在文法中没有定义为非终结符,但是本程序将其等用于新的非终结符进行解析。 8 | * 输出调试信息时会针对这个类型进行处理,以保证不会输出到日志中 9 | *

10 | */ 11 | public enum GUNIT { 12 | /* 忽略了 BlockItem, BType, Decl三个非终结符 */ 13 | CompUnit, 14 | ConstDecl, 15 | VarDecl, 16 | ConstDef, 17 | ConstInitVal, 18 | VarDef, 19 | InitVal, 20 | FuncDef, 21 | MainFuncDef, 22 | FuncType, 23 | FuncFParams, 24 | FuncFParam, 25 | Block, 26 | Stmt, 27 | Exp, 28 | Cond, 29 | LVal, 30 | PrimaryExp, 31 | Number, 32 | UnaryExp, 33 | UnaryOp, 34 | FuncRParams, 35 | MulExp, 36 | AddExp, 37 | RelExp, 38 | EqExp, 39 | LAndExp, 40 | LOrExp, 41 | ConstExp, 42 | // 以下都是不需要输出的GUnit类型 43 | BlockItem, 44 | BType, 45 | Decl, 46 | } 47 | -------------------------------------------------------------------------------- /src/component/Label.java: -------------------------------------------------------------------------------- 1 | package component; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * Label 标签类 7 | * 你可以把他理解成String类这种全局的类 8 | * 把它放在component下感觉比较合理(笑 9 | */ 10 | public class Label { 11 | public String labelName; 12 | public Label(String name){ 13 | this.labelName = name; 14 | } 15 | 16 | @Override 17 | public boolean equals(Object o) { 18 | if (this == o) return true; 19 | if (o == null || getClass() != o.getClass()) return false; 20 | Label label = (Label) o; 21 | return Objects.equals(labelName, label.labelName); 22 | } 23 | 24 | @Override 25 | public int hashCode() { 26 | return Objects.hash(labelName); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/component/LineContainer.java: -------------------------------------------------------------------------------- 1 | package component; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class LineContainer { 6 | private ArrayList contain; 7 | 8 | public LineContainer() { 9 | this.contain = new ArrayList<>(); 10 | } 11 | 12 | public void addLine(String l) { 13 | this.contain.add(l + "\n"); 14 | } 15 | 16 | public String dump() { 17 | StringBuilder ret = new StringBuilder(); 18 | for (String l : contain) { 19 | ret.append(l); 20 | } 21 | return ret.toString(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/component/SYMBOL.java: -------------------------------------------------------------------------------- 1 | package component; 2 | 3 | /** 4 | * component.SYMBOL 词法类型枚举类 5 | * 6 | * @author neumy 7 | * @version jdk1.8.0 8 | */ 9 | public enum SYMBOL { 10 | UNKNOWN, 11 | IDENFR, 12 | INTCON, 13 | STRCON, 14 | MAINTK, 15 | CONSTTK, 16 | INTTK, 17 | BREAKTK, 18 | CONTINUETK, 19 | IFTK, 20 | ELSETK, 21 | NOT, 22 | AND, 23 | OR, 24 | WHILETK, 25 | GETINTTK, 26 | PRINTFTK, 27 | RETURNTK, 28 | PLUS, 29 | MINU, 30 | VOIDTK, 31 | MULT, 32 | DIV, 33 | MOD, 34 | LSS, // < 35 | LEQ, // <= 36 | GRE, // > 37 | GEQ, // >= 38 | EQL, // == 39 | NEQ, // != 40 | ASSIGN, // = 41 | SEMICN, // ; 42 | COMMA, // , 43 | LPARENT, // ( 44 | RPARENT, // ) 45 | LBRACK, // [ 46 | RBRACK, // ] 47 | LBRACE, // { 48 | RBRACE, // } 49 | IGNORE // 注释 50 | } 51 | -------------------------------------------------------------------------------- /src/component/Token.java: -------------------------------------------------------------------------------- 1 | package component; 2 | 3 | /** 4 | * component.Token 词类 5 | * 管理当前词的内容(字符串形式)、词法类型和所在行 6 | * 7 | * @author neumy 8 | * @version jdk1.8.0 9 | */ 10 | public class Token { 11 | private SYMBOL symbol; 12 | private String value; 13 | private Integer line; 14 | 15 | public Token(SYMBOL symbol, String value, Integer line) { 16 | this.symbol = symbol; 17 | this.value = value; 18 | this.line = line; 19 | } 20 | 21 | public Integer getLine() { 22 | return line.intValue(); 23 | } 24 | 25 | public String getValue() { 26 | return value; 27 | } 28 | 29 | public SYMBOL getSymbol() { 30 | return symbol; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return this.line + ": " + 36 | this.symbol + " " + this.value; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/component/datatype/ArrayType.java: -------------------------------------------------------------------------------- 1 | package component.datatype; 2 | 3 | import global.Error; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Objects; 7 | 8 | public class ArrayType implements Datatype { 9 | public Datatype basicType; 10 | public ArrayList dimension; 11 | 12 | public ArrayType(Datatype basicType, ArrayList dimensions) { 13 | this.basicType = basicType; 14 | this.dimension = dimensions; 15 | } 16 | 17 | @Override 18 | public boolean equals(Object o) { 19 | if (this == o) return true; 20 | if (o == null || getClass() != o.getClass()) return false; 21 | ArrayType arrayType = (ArrayType) o; 22 | return Objects.equals(basicType, arrayType.basicType) && 23 | Objects.equals(dimension.size(), arrayType.dimension.size()); 24 | } 25 | 26 | @Override 27 | public Integer spaceSize() { 28 | return flat() * this.basicType.spaceSize(); 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | StringBuilder temp = new StringBuilder(); 34 | for (Integer len : dimension) { 35 | temp.append("[" + len + "]"); 36 | } 37 | return this.basicType + temp.toString(); 38 | } 39 | 40 | public Integer flat() { 41 | int length = 1; 42 | for (Integer len : this.dimension) { 43 | if (len == null) Error.warning("flat should not be used when dimensions are in-complete"); 44 | length *= len; 45 | } 46 | return length; 47 | } 48 | 49 | public Datatype getChildType() { 50 | ArrayList tmp = new ArrayList<>(); 51 | for (int i = 1; i < this.dimension.size(); i++) { 52 | tmp.add(this.dimension.get(i)); 53 | } 54 | if(tmp.size() == 0){ 55 | return this.basicType; 56 | } 57 | return new ArrayType(this.basicType, tmp); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/component/datatype/Datatype.java: -------------------------------------------------------------------------------- 1 | package component.datatype; 2 | 3 | public interface Datatype { 4 | String toString(); 5 | boolean equals(Object o); 6 | Integer spaceSize(); 7 | } 8 | -------------------------------------------------------------------------------- /src/component/datatype/IntType.java: -------------------------------------------------------------------------------- 1 | package component.datatype; 2 | 3 | public class IntType implements Datatype { 4 | 5 | public IntType() { 6 | ; 7 | } 8 | 9 | @Override 10 | public boolean equals(Object obj) { 11 | return obj instanceof IntType; 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return "int"; 17 | } 18 | 19 | @Override 20 | public Integer spaceSize() { 21 | return 4; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/component/datatype/VoidType.java: -------------------------------------------------------------------------------- 1 | package component.datatype; 2 | 3 | import global.Error; 4 | 5 | public class VoidType implements Datatype { 6 | 7 | @Override 8 | public String toString() { 9 | return "void"; 10 | } 11 | 12 | @Override 13 | public boolean equals(Object o) { 14 | return false; 15 | } 16 | 17 | @Override 18 | public Integer spaceSize() { 19 | Error.warning("you are querying an void type's spaceSize!"); 20 | return 0; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/component/graph/Graph.java: -------------------------------------------------------------------------------- 1 | package component.graph; 2 | 3 | import global.Config; 4 | import mips.register.Register; 5 | import symbolstruct.entries.Entry; 6 | 7 | import java.util.*; 8 | 9 | public class Graph { 10 | public HashMap nodes; 11 | public Stack stack; 12 | public List> list; 13 | 14 | public Graph(List> list) { 15 | this.nodes = new HashMap<>(); 16 | this.stack = new Stack<>(); 17 | this.list = list; 18 | } 19 | 20 | public void addNode(Entry entry) { 21 | if (!nodes.containsKey(entry)) { 22 | this.nodes.put(entry, new Node(entry)); 23 | } 24 | } 25 | 26 | public void addEdge(Entry a, Entry b) { 27 | Node nodeA = nodes.get(a); 28 | Node nodeB = nodes.get(b); 29 | nodeA.connects.add(nodeB); 30 | nodeB.connects.add(nodeA); 31 | } 32 | 33 | public void executeDistribution() { 34 | ArrayList regs = Config.getGlbReg(); 35 | 36 | if(this.nodes.size() == 0) { 37 | return; 38 | } 39 | 40 | // 删除连接数小于K的节点,直到剩下最后一个节点 41 | while (nodes.size() > 1) { 42 | Node toRemove = null; 43 | for (Map.Entry entry : this.nodes.entrySet()) { 44 | Node node = (Node) entry.getValue(); 45 | int counter = 0; 46 | for (Node otherNode : node.connects) { 47 | if (nodes.containsKey(otherNode.entry)) { 48 | counter++; 49 | } 50 | } 51 | if (counter < regs.size()) { 52 | toRemove = node; 53 | break; 54 | } 55 | } 56 | 57 | if (toRemove != null) { 58 | stack.add(toRemove); 59 | nodes.remove(toRemove.entry); 60 | } else { 61 | // 如果检查一遍发现没有任何节点连接数小于k,那么遍历引用计数找到计数最少的一个Entry,并移除 62 | Entry noDistribute = null; 63 | for (Map.Entry entry : this.list) { 64 | if (this.nodes.containsKey(entry.getKey())) { 65 | noDistribute = (Entry) entry.getKey(); 66 | break; 67 | } 68 | } 69 | nodes.remove(noDistribute); 70 | } 71 | } 72 | 73 | Node lastNode = (Node) this.nodes.values().toArray()[0]; 74 | lastNode.reg = regs.get(0); 75 | 76 | // 按移除的顺序的逆序,将节点一个个取出 77 | while (stack.size() > 0) { 78 | Node toAdd = stack.pop(); 79 | HashSet tmpRegs = new HashSet<>(regs); 80 | for (Node connNode : toAdd.connects) { 81 | // 对需要添加的节点的每条边,如果另一方处在当前图中,则移除其对应的寄存器 82 | if (nodes.containsKey(connNode.entry)) { 83 | tmpRegs.remove(connNode.reg); 84 | } 85 | } 86 | // 选取剩下的寄存器中的最后一个 87 | toAdd.reg = (Register) tmpRegs.toArray()[0]; 88 | // 将需要添加的点加入图中 89 | nodes.put(toAdd.entry, toAdd); 90 | } 91 | } 92 | 93 | public HashMap dump() { 94 | HashMap distribution = new HashMap<>(); 95 | for (Entry entry : this.nodes.keySet()) { 96 | distribution.put(entry, this.nodes.get(entry).reg); 97 | } 98 | return distribution; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/component/graph/Node.java: -------------------------------------------------------------------------------- 1 | package component.graph; 2 | 3 | import mips.register.Register; 4 | import symbolstruct.entries.Entry; 5 | 6 | import java.util.HashSet; 7 | import java.util.Objects; 8 | 9 | public class Node { 10 | public HashSet connects; 11 | public Entry entry; 12 | public Register reg; 13 | 14 | public Node(Entry entry) { 15 | this.connects = new HashSet<>(); 16 | this.entry = entry; 17 | } 18 | 19 | @Override 20 | public boolean equals(Object o) { 21 | if (this == o) return true; 22 | if (o == null || getClass() != o.getClass()) return false; 23 | Node node = (Node) o; 24 | return Objects.equals(entry, node.entry); 25 | } 26 | 27 | @Override 28 | public int hashCode() { 29 | return Objects.hash(entry); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/component/narray/ConstNArray.java: -------------------------------------------------------------------------------- 1 | package component.narray; 2 | 3 | import component.datatype.Datatype; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class ConstNArray extends NArray { 8 | 9 | public ConstNArray(Datatype datatype, ArrayList values) { 10 | super(datatype, values); 11 | for (NArrayItem item : values) { 12 | assert item instanceof NInt; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/component/narray/NArray.java: -------------------------------------------------------------------------------- 1 | package component.narray; 2 | 3 | import component.datatype.ArrayType; 4 | import component.datatype.Datatype; 5 | import global.Error; 6 | import symbolstruct.entries.VarEntry; 7 | 8 | import java.util.ArrayList; 9 | 10 | public class NArray { 11 | private ArrayList values; 12 | private ArrayType datatype; 13 | 14 | public NArray(Datatype datatype, ArrayList values) { 15 | this.datatype = (ArrayType) datatype; 16 | assert values.size() == this.datatype.flat(); 17 | this.values = values; 18 | } 19 | 20 | public ArrayList getValues() { 21 | return values; 22 | } 23 | 24 | public ArrayType getDatatype() { 25 | return datatype; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/component/narray/NArrayItem.java: -------------------------------------------------------------------------------- 1 | package component.narray; 2 | 3 | public interface NArrayItem { 4 | Object instance(); 5 | } 6 | -------------------------------------------------------------------------------- /src/component/narray/NInt.java: -------------------------------------------------------------------------------- 1 | package component.narray; 2 | 3 | public class NInt implements NArrayItem { 4 | private Integer value; 5 | 6 | public NInt(Integer value) { 7 | this.value = value; 8 | } 9 | 10 | @Override 11 | public Object instance() { 12 | return value; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/component/narray/NPos.java: -------------------------------------------------------------------------------- 1 | package component.narray; 2 | 3 | import symbolstruct.entries.Entry; 4 | import symbolstruct.entries.VarEntry; 5 | 6 | import java.util.ArrayList; 7 | 8 | /** 9 | * 用于描述数组中元素位置的对象 10 | */ 11 | public class NPos { 12 | private ArrayList pos; 13 | public NPos(ArrayList pos){ 14 | this.pos = pos; 15 | } 16 | 17 | public Integer getDims(){ 18 | return this.pos.size(); 19 | } 20 | 21 | public VarEntry getOnDim(Integer dim) { 22 | return this.pos.get(dim); 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | StringBuilder builder = new StringBuilder(); 28 | for (VarEntry e:this.pos) { 29 | builder.append(String.format("[%s]", e.name)); 30 | } 31 | return builder.toString(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/exceptions/DuplicatedDefineException.java: -------------------------------------------------------------------------------- 1 | package exceptions; 2 | 3 | public class DuplicatedDefineException extends Exception { 4 | public DuplicatedDefineException() { 5 | super(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/exceptions/GramParseException.java: -------------------------------------------------------------------------------- 1 | package exceptions; 2 | 3 | 4 | import component.GUNIT; 5 | import component.Token; 6 | 7 | public class GramParseException extends Exception { 8 | String mess; 9 | private GramParseException from; 10 | private Token curToken; 11 | private int level; 12 | 13 | public GramParseException(String mess) { 14 | this.from = null; 15 | this.mess = mess; 16 | } 17 | 18 | public GramParseException(GramParseException e, Token curToken, int level, GUNIT curGUnit) { 19 | this.from = e; 20 | this.curToken = curToken; 21 | this.level = level; 22 | this.mess = "Fail to execute grammar parse for LINE:" + curToken.getLine() + 23 | " VALUE:" + curToken.getValue() + "\tin LEVEL: " + level + "\tGUNIT: "+curGUnit; 24 | } 25 | 26 | @Override 27 | public String getMessage() { 28 | return this.mess; 29 | } 30 | 31 | public GramParseException getFrom() { 32 | return from; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | StringBuilder temp = new StringBuilder(); 38 | for (int i = 0; i < level; i++) { 39 | temp.append(' '); 40 | } 41 | temp.append(curToken.getLine() + " " + curToken.getValue() + " in level:" + level + "\t" + mess +"\n"); 42 | return temp.toString(); 43 | } 44 | 45 | public Token getCurToken() { 46 | return curToken; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/global/Config.java: -------------------------------------------------------------------------------- 1 | package global; 2 | 3 | import mips.register.Register; 4 | 5 | import javax.lang.model.type.ArrayType; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | 11 | /** 12 | * Config是全局常量类,遵循单例模式 13 | */ 14 | public class Config { 15 | public static String inputFilePath = "testfile.txt"; 16 | public static String LexParserLogPath = "lex_output.txt"; 17 | public static String GramParserLogPath = "output.txt"; 18 | public static String SymbolLogPath = "symbols.txt"; 19 | public static String ErrorLogPath = "error.txt"; 20 | public static String MIPSLogPath = "mips.txt"; 21 | public static String IMExpLogPath = "imexp.txt"; 22 | private static Integer tmpNameSed = 0; 23 | public static long ProgramInitTime = System.currentTimeMillis(); 24 | 25 | public static Integer getTmpNameSed() { 26 | return tmpNameSed++; 27 | } 28 | 29 | public static ArrayList getGlbReg() { 30 | Register[] regs = new Register[]{ 31 | Register.$s0, 32 | Register.$s1, 33 | Register.$s2, 34 | Register.$s3, 35 | Register.$s4, 36 | Register.$s5, 37 | Register.$s6, 38 | Register.$s7, 39 | Register.$a1, 40 | Register.$a2, 41 | Register.$a3, 42 | Register.$v1, 43 | Register.$gp, 44 | Register.$t8, 45 | Register.$t9, 46 | Register.$t5, 47 | Register.$t6, 48 | Register.$t7 49 | }; 50 | ArrayList ret = new ArrayList(); 51 | Collections.addAll(ret, regs); 52 | return ret; 53 | } 54 | 55 | public static ArrayList getLocReg() { 56 | Register[] regs = new Register[]{ 57 | Register.$t0, 58 | Register.$t1, 59 | Register.$t2, 60 | Register.$t3, 61 | Register.$t4 62 | }; 63 | ArrayList ret = new ArrayList(); 64 | Collections.addAll(ret, regs); 65 | return ret; 66 | } 67 | 68 | public static Integer PowerOfTwo(int n) { 69 | if (n > 0 && (n & (n - 1)) == 0) { 70 | return (int) (Math.log(n) / Math.log(2)); 71 | } 72 | return null; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/global/Error.java: -------------------------------------------------------------------------------- 1 | package global; 2 | 3 | import component.SYMBOL; 4 | 5 | /** 6 | * Error是工具类,用于提供所有错误处理的方法 7 | * 其可以调用Logger打印日志,也可以同时向控制台进行输出 8 | * 9 | * @author neumy 10 | * @version jdk1.8.0 11 | */ 12 | public class Error { 13 | public static void lexError(int line, SYMBOL symbol) { 14 | String message = "LexParseError happened when parsing " + symbol.toString() + " in line " + line; 15 | System.out.println(message); 16 | } 17 | 18 | public static void grammarError(int line, String abStr) { 19 | String message = "GrammarParseError happened when parsing \"" + abStr + "\" in line " + line; 20 | System.out.println(message); 21 | } 22 | 23 | public static String formatStringError(int line) { 24 | return (line + " a"); 25 | } 26 | 27 | public static void warning(String message) { 28 | System.out.println("[Warning]: " + message);throw new RuntimeException("[Warning]: " + message); 29 | } 30 | 31 | public static String duplicatedDefinitionError(int line) { 32 | return (line + " b"); 33 | } 34 | 35 | public static String undefinedError(int line) { 36 | return (line + " c"); 37 | } 38 | 39 | public static String parameterAmountError(int line) { 40 | return (line + " d"); 41 | } 42 | 43 | public static String parameterTypeError(int line) { 44 | return (line + " e"); 45 | } 46 | 47 | public static String voidFuncButReturnError(int line) { 48 | return (line + " f"); 49 | } 50 | 51 | public static String intFuncButNoReturnError(int line) { 52 | return (line + " g"); 53 | } 54 | 55 | public static String modifiedConstError(int line) { 56 | return (line + " h"); 57 | } 58 | 59 | public static String semiconMissingError(int line) { 60 | return (line + " i"); 61 | } 62 | 63 | public static String leftParentMissingError(int line) { 64 | return (line + " j"); 65 | } 66 | 67 | public static String leftBraketMissingError(int line) { 68 | return (line + " k"); 69 | } 70 | 71 | public static String printfExpAmountError(int line) { 72 | return (line + " l"); 73 | } 74 | 75 | public static String breakContinueError(int line) { 76 | return (line + " m"); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/global/Logger.java: -------------------------------------------------------------------------------- 1 | package global; 2 | 3 | import component.SYMBOL; 4 | import imcode.imexp.IMExp; 5 | 6 | import java.io.File; 7 | import java.io.FileWriter; 8 | import java.util.ArrayList; 9 | import java.util.Comparator; 10 | 11 | /** 12 | * Logger是全局日志记录,遵循单例模式 13 | * 管理所有具体日志信息的输入格式和文件 14 | * 15 | * @author neumy 16 | * @version jdk1.8.0 17 | */ 18 | public class Logger { 19 | private static Logger logger; 20 | private String LexParserLogPath; 21 | private FileWriter LexParserLogWriter; 22 | private String GramParserLogPath; 23 | private FileWriter GramParserLogWriter; 24 | private String ErrorLogPath; 25 | private FileWriter ErrorLogWriter; 26 | private String SymbolLogPath; 27 | private FileWriter SymbolLogWriter; 28 | private ArrayList ErrorLogBuffer; 29 | private String MIPSLogPath; 30 | private FileWriter MIPSLogWriter; 31 | private String IMExpLogPath; 32 | private FileWriter IMExpLogWriter; 33 | 34 | class ErrorMessage { 35 | Integer line; 36 | String message; 37 | 38 | ErrorMessage(Integer a, String message) { 39 | this.line = a; 40 | this.message = message; 41 | 42 | } 43 | } 44 | 45 | public static Logger GetLogger() { 46 | if (logger == null) { 47 | logger = new Logger(); 48 | } 49 | return logger; 50 | } 51 | 52 | private Logger() { 53 | try { 54 | this.LexParserLogPath = Config.LexParserLogPath; 55 | this.LexParserLogWriter = new FileWriter(new File(this.LexParserLogPath)); 56 | this.GramParserLogPath = Config.GramParserLogPath; 57 | this.GramParserLogWriter = new FileWriter(new File(this.GramParserLogPath)); 58 | this.SymbolLogPath = Config.SymbolLogPath; 59 | this.SymbolLogWriter = new FileWriter(new File(this.SymbolLogPath)); 60 | this.ErrorLogPath = Config.ErrorLogPath; 61 | this.ErrorLogWriter = new FileWriter(new File(this.ErrorLogPath)); 62 | this.ErrorLogBuffer = new ArrayList<>(); 63 | this.MIPSLogPath = Config.MIPSLogPath; 64 | this.MIPSLogWriter = new FileWriter(new File(this.MIPSLogPath)); 65 | this.IMExpLogPath = Config.IMExpLogPath; 66 | this.IMExpLogWriter = new FileWriter(new File((this.IMExpLogPath))); 67 | } catch (Exception e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | public void ErrorLog(String string) { 73 | Integer line = Integer.valueOf(string.split(" ")[0]); 74 | ErrorLogBuffer.add(new ErrorMessage(line, string)); 75 | } 76 | 77 | public void DumpError() { 78 | ErrorLogBuffer.sort(new Comparator() { 79 | @Override 80 | public int compare(ErrorMessage o1, ErrorMessage o2) { 81 | if (o1.line >= o2.line) { 82 | return 1; 83 | } else { 84 | return -1; 85 | } 86 | } 87 | }); 88 | ErrorMessage former = null; 89 | for (ErrorMessage message : ErrorLogBuffer) { 90 | if (former != null) { 91 | if (former.line == message.line) { 92 | continue; 93 | } 94 | } 95 | try { 96 | this.ErrorLogWriter.write(message.message + "\n"); 97 | this.ErrorLogWriter.flush(); 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | } 101 | former = message; 102 | } 103 | } 104 | 105 | public void LexParserLog(SYMBOL d, String value) { 106 | try { 107 | this.LexParserLogWriter.write(d.toString() + " " + value + "\n"); 108 | this.LexParserLogWriter.flush(); 109 | } catch (Exception e) { 110 | e.printStackTrace(); 111 | } 112 | } 113 | 114 | public void GrammarLog(String str) { 115 | try { 116 | this.GramParserLogWriter.write(str + "\n"); 117 | this.GramParserLogWriter.flush(); 118 | } catch (Exception e) { 119 | e.printStackTrace(); 120 | } 121 | } 122 | 123 | public void SymbolLog(String str) { 124 | try { 125 | this.SymbolLogWriter.write(str + "\n"); 126 | this.SymbolLogWriter.flush(); 127 | } catch (Exception e) { 128 | e.printStackTrace(); 129 | } 130 | } 131 | 132 | public void MIPSLog(String str) { 133 | try { 134 | this.MIPSLogWriter.write(str + "\n"); 135 | this.MIPSLogWriter.flush(); 136 | } catch (Exception e) { 137 | e.printStackTrace(); 138 | } 139 | } 140 | 141 | public void IMExpLogPath(String exp) { 142 | try { 143 | this.IMExpLogWriter.write(exp + "\n"); 144 | this.IMExpLogWriter.flush(); 145 | } catch (Exception e) { 146 | e.printStackTrace(); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/imcode/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neumyor/C_Complier_on_Java/2ce325a4abf677eee111281d8fddf122ab1a6491/src/imcode/.DS_Store -------------------------------------------------------------------------------- /src/imcode/imexp/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neumyor/C_Complier_on_Java/2ce325a4abf677eee111281d8fddf122ab1a6491/src/imcode/imexp/.DS_Store -------------------------------------------------------------------------------- /src/imcode/imexp/AddExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import improve.component.regpool.RegPool; 4 | import symbolstruct.FuncRegion; 5 | 6 | import component.LineContainer; 7 | import imcode.imitem.IMItem; 8 | import imcode.imitem.IntItem; 9 | import imcode.imitem.VarItem; 10 | import symbolstruct.CodeText; 11 | import symbolstruct.FuncRegion; 12 | import symbolstruct.entries.ConstValueEntry; 13 | import symbolstruct.entries.Entry; 14 | 15 | /** 16 | * 所有计算类四元式 17 | * item1必须是变量 18 | * item2、3也必须是变量 19 | */ 20 | public class AddExp extends IMExp { 21 | protected AddExp(IMItem item1, IMItem item2, IMItem item3) { 22 | assert item1 instanceof VarItem; 23 | assert item2 instanceof VarItem; 24 | assert item3 instanceof VarItem; 25 | this.item1 = item1; 26 | this.item2 = item2; 27 | this.item3 = item3; 28 | } 29 | 30 | @Override 31 | public void toCode(RegPool pool) { 32 | LineContainer ret = new LineContainer(); 33 | 34 | Entry a = ((VarItem) this.item2).entry; 35 | Entry b = ((VarItem) this.item3).entry; 36 | Entry toAssign = ((VarItem) this.item1).entry; 37 | 38 | if (a instanceof ConstValueEntry && b instanceof ConstValueEntry) { 39 | ret.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), 40 | ((Integer) ((ConstValueEntry) a).getValue()) + ((Integer) ((ConstValueEntry) b).getValue()))); 41 | } else if (a instanceof ConstValueEntry) { 42 | String bReg = pool.find(b); 43 | ret.addLine(String.format("addi %s, %s, %d", 44 | pool.findNoLoad(toAssign), bReg, ((ConstValueEntry) a).getValue())); 45 | } else if (b instanceof ConstValueEntry) { 46 | String aReg = pool.find(a); 47 | ret.addLine(String.format("addi %s, %s, %d", 48 | pool.findNoLoad(toAssign), aReg, ((ConstValueEntry) b).getValue())); 49 | } else{ 50 | String aReg = pool.find(a); 51 | String bReg = pool.find(b); 52 | ret.addLine(String.format("add %s, %s, %s", pool.findNoLoad(toAssign), aReg, bReg)); 53 | } 54 | 55 | CodeText.textNLine(ret.dump()); 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | String a = null; 61 | if (this.item2 instanceof IntItem) { 62 | a = String.valueOf(((IntItem) this.item2).intValue); 63 | } else if (this.item2 instanceof VarItem) { 64 | a = ((VarItem) this.item2).entry.name; 65 | } 66 | 67 | String b = null; 68 | if (this.item3 instanceof IntItem) { 69 | b = String.valueOf(((IntItem) this.item3).intValue); 70 | } else if (this.item3 instanceof VarItem) { 71 | b = ((VarItem) this.item3).entry.name; 72 | } 73 | String it = ((VarItem) this.item1).entry.name; 74 | return it + " = " + a + " + " + b; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/imcode/imexp/AssignByGetInt.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import improve.component.regpool.RegPool; 5 | import symbolstruct.CodeText; 6 | import symbolstruct.FuncRegion; 7 | 8 | import imcode.imitem.IMItem; 9 | import imcode.imitem.VarItem; 10 | import symbolstruct.entries.Entry; 11 | 12 | /** 13 | * 将getint()的值赋值给一个变量 14 | * item1必须是变量类型 15 | */ 16 | public class AssignByGetInt extends IMExp { 17 | protected AssignByGetInt(IMItem toAssign) { 18 | assert toAssign instanceof VarItem; 19 | this.item1 = toAssign; 20 | this.item2 = this.item3 = null; 21 | } 22 | 23 | @Override 24 | public void toCode(RegPool pool) { 25 | LineContainer c = new LineContainer(); 26 | 27 | Entry toAssign = ((VarItem) this.item1).entry; 28 | c.addLine("li $v0, 5"); 29 | c.addLine("syscall"); 30 | c.addLine(String.format("add %s, $v0, $0", pool.findNoLoad(toAssign))); 31 | 32 | 33 | CodeText.textNLine(c.dump()); 34 | return; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | String toa = ((VarItem) this.item1).entry.name; 40 | return toa + " = getint()"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/imcode/imexp/AssignByRetExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import improve.component.regpool.RegPool; 5 | import symbolstruct.CodeText; 6 | 7 | import imcode.imitem.IMItem; 8 | import imcode.imitem.VarItem; 9 | import symbolstruct.entries.Entry; 10 | 11 | /** 12 | * 在调用函数后,从$v0寄存器获取返回值 13 | */ 14 | public class AssignByRetExp extends IMExp { 15 | protected AssignByRetExp(IMItem var) { 16 | assert var instanceof VarItem; 17 | this.item1 = var; 18 | this.item2 = this.item3 = null; 19 | } 20 | 21 | @Override 22 | public void toCode(RegPool pool) { 23 | Entry toa = ((VarItem) this.item1).entry; 24 | LineContainer c = new LineContainer(); 25 | 26 | c.addLine(String.format("add %s, $v0, $0", pool.findNoLoad(toa))); 27 | 28 | CodeText.textNLine(c.dump()); 29 | return; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | String ret = ((VarItem) this.item1).entry.name; 35 | return ret + " = " + "$v0"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/imcode/imexp/AssignByVarAddrExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import imcode.imitem.SpaceItem; 5 | import improve.component.regpool.RegPool; 6 | import symbolstruct.CodeText; 7 | import symbolstruct.FuncRegion; 8 | 9 | import imcode.imitem.IMItem; 10 | import imcode.imitem.VarItem; 11 | import symbolstruct.entries.Entry; 12 | 13 | /** 14 | * 将变量的地址赋值给另一个变量 15 | * 要求item1、2都是变量 16 | */ 17 | public class AssignByVarAddrExp extends IMExp { 18 | protected AssignByVarAddrExp(IMItem array, IMItem offset) { 19 | assert array instanceof VarItem; 20 | assert offset instanceof SpaceItem; 21 | this.item1 = array; 22 | this.item2 = offset; 23 | this.item3 = null; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | String itm1 = ((VarItem) this.item1).entry.name; 29 | String itm2 = ((SpaceItem) this.item2).entry.name; 30 | return itm1 + " = " + "addr<" + itm2 + ">"; 31 | } 32 | 33 | @Override 34 | public void toCode(RegPool pool) { 35 | Entry itm1 = ((VarItem) this.item1).entry; 36 | Entry itm2 = ((SpaceItem) this.item2).entry; 37 | LineContainer c = new LineContainer(); 38 | 39 | if (itm2.isGlobal()) { 40 | c.addLine(String.format("la %s, %s", pool.findNoLoad(itm1), itm2.name)); 41 | } else { 42 | c.addLine(String.format("addi %s, $sp, %d", pool.findNoLoad(itm1), pool.getFrame().offsetMap.get(itm2))); 43 | } 44 | 45 | CodeText.textNLine(c.dump()); 46 | return; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/imcode/imexp/AssignByVarExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import imcode.imitem.IntItem; 5 | import improve.component.regpool.RegPool; 6 | import symbolstruct.CodeText; 7 | import symbolstruct.FuncRegion; 8 | 9 | import imcode.imitem.IMItem; 10 | import imcode.imitem.VarItem; 11 | import symbolstruct.FuncRegion; 12 | import symbolstruct.entries.ConstValueEntry; 13 | import symbolstruct.entries.Entry; 14 | 15 | public class AssignByVarExp extends IMExp { 16 | protected AssignByVarExp(IMItem toAssign, IMItem value) { 17 | assert toAssign instanceof VarItem; 18 | assert value instanceof VarItem; 19 | this.item1 = toAssign; 20 | this.item2 = value; 21 | } 22 | 23 | @Override 24 | public void toCode(RegPool pool) { 25 | LineContainer c = new LineContainer(); 26 | Entry toAssign = ((VarItem) this.item1).entry; 27 | Entry from = ((VarItem) this.item2).entry; 28 | 29 | if (from instanceof ConstValueEntry) { 30 | c.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), ((ConstValueEntry) from).getValue())); 31 | } else { 32 | String fromReg = pool.find(from); 33 | c.addLine(String.format("add %s, %s, $0", pool.findNoLoad(toAssign), fromReg)); 34 | } 35 | 36 | CodeText.textNLine(c.dump()); 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | String a = ((VarItem) this.item1).entry.name; 42 | 43 | String b = ((VarItem) this.item2).entry.name; 44 | 45 | return a + " = " + b; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/imcode/imexp/AssignFromAddrExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import imcode.imitem.IMItem; 5 | import imcode.imitem.VarItem; 6 | import improve.component.regpool.RegPool; 7 | import symbolstruct.CodeText; 8 | import symbolstruct.FuncRegion; 9 | import symbolstruct.entries.Entry; 10 | 11 | public class AssignFromAddrExp extends IMExp{ 12 | protected AssignFromAddrExp(IMItem addr, IMItem value) { 13 | assert addr instanceof VarItem; 14 | assert value instanceof VarItem; 15 | this.item1 = value; 16 | this.item2 = addr; 17 | } 18 | 19 | @Override 20 | public void toCode(RegPool pool) { 21 | Entry value = ((VarItem) this.item1).entry; 22 | Entry addr = ((VarItem) this.item2).entry; 23 | LineContainer c = new LineContainer(); 24 | 25 | String addrReg = pool.find(addr); 26 | c.addLine(String.format("lw %s, (%s)", pool.findNoLoad(value), addrReg)); 27 | 28 | CodeText.textNLine(c.dump()); 29 | return ; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | String value = ((VarItem) this.item1).entry.name; 35 | String addr = ((VarItem) this.item2).entry.name; 36 | return String.format("%s <- [%s]", value, addr); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/imcode/imexp/AssignToAddrExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import imcode.imitem.IMItem; 4 | import imcode.imitem.VarItem; 5 | import improve.component.regpool.RegPool; 6 | import symbolstruct.CodeText; 7 | import symbolstruct.entries.ConstValueEntry; 8 | import symbolstruct.entries.Entry; 9 | 10 | public class AssignToAddrExp extends IMExp { 11 | protected AssignToAddrExp(IMItem addr, IMItem value) { 12 | assert addr instanceof VarItem; 13 | assert value instanceof VarItem; 14 | this.item2 = addr; 15 | this.item3 = value; 16 | } 17 | 18 | @Override 19 | public void toCode(RegPool pool) { 20 | Entry addr = ((VarItem) this.item2).entry; 21 | Entry value = ((VarItem) this.item3).entry; 22 | 23 | if (value instanceof ConstValueEntry) { 24 | String regStr = pool.allocTmpReg(); 25 | CodeText.textNLine(String.format("li %s, %d", regStr, ((ConstValueEntry) value).getValue())); 26 | CodeText.textNLine(String.format("sw %s, (%s)", regStr, pool.find(addr))); 27 | pool.freeTmpReg(regStr); 28 | } else { 29 | CodeText.textNLine(String.format("sw %s, (%s)", pool.find(value), pool.find(addr))); 30 | } 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | String addr = ((VarItem) this.item2).entry.name; 36 | String value = ((VarItem) this.item3).entry.name; 37 | return String.format("[%s] <- %s", addr, value); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/imcode/imexp/BeqExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import global.Config; 5 | import imcode.imitem.VarItem; 6 | import improve.component.regpool.RegPool; 7 | import symbolstruct.CodeText; 8 | 9 | import imcode.imitem.IMItem; 10 | import symbolstruct.entries.ConstValueEntry; 11 | import symbolstruct.entries.Entry; 12 | 13 | import java.util.Objects; 14 | 15 | public class BeqExp extends IMExp { 16 | protected BeqExp(IMItem item1, IMItem item2, IMItem item3) { 17 | assert item1 instanceof VarItem; 18 | assert item2 instanceof VarItem; 19 | assert item3 instanceof VarItem; 20 | this.item1 = item1; 21 | this.item2 = item2; 22 | this.item3 = item3; 23 | } 24 | 25 | @Override 26 | public void toCode(RegPool pool) { 27 | LineContainer ret = new LineContainer(); 28 | 29 | Entry toAssign = ((VarItem) this.item1).entry; 30 | Entry a = ((VarItem) this.item2).entry; 31 | Entry b = ((VarItem) this.item3).entry; 32 | 33 | if (a instanceof ConstValueEntry && b instanceof ConstValueEntry) { 34 | Integer aValue = (Integer) ((ConstValueEntry) a).getValue(); 35 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 36 | Integer boolValue = (Objects.equals(aValue, bValue)) ? 1 : 0; 37 | ret.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), boolValue)); 38 | } else if (a instanceof ConstValueEntry) { 39 | String bReg = pool.find(b); 40 | Integer aValue = (Integer) ((ConstValueEntry) a).getValue(); 41 | ret.addLine(String.format("seq %s, %s, %d", pool.findNoLoad(toAssign), bReg, aValue)); 42 | } else if (b instanceof ConstValueEntry) { 43 | String aReg = pool.find(a); 44 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 45 | ret.addLine(String.format("seq %s, %s, %d", pool.findNoLoad(toAssign), aReg, bValue)); 46 | } else { 47 | String aReg = pool.find(a); 48 | String bReg = pool.find(b); 49 | ret.addLine(String.format("seq %s, %s, %s", pool.findNoLoad(toAssign), aReg, bReg)); 50 | } 51 | 52 | CodeText.textNLine(ret.dump()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/imcode/imexp/BgeExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import global.Config; 5 | import imcode.imitem.VarItem; 6 | import improve.component.regpool.RegPool; 7 | import symbolstruct.CodeText; 8 | 9 | import imcode.imitem.IMItem; 10 | import symbolstruct.entries.ConstValueEntry; 11 | import symbolstruct.entries.Entry; 12 | 13 | public class BgeExp extends IMExp { 14 | protected BgeExp(IMItem item1, IMItem item2, IMItem item3) { 15 | assert item1 instanceof VarItem; 16 | assert item2 instanceof VarItem; 17 | assert item3 instanceof VarItem; 18 | this.item1 = item1; 19 | this.item2 = item2; 20 | this.item3 = item3; 21 | } 22 | 23 | @Override 24 | public void toCode(RegPool pool) { 25 | LineContainer ret = new LineContainer(); 26 | 27 | Entry toAssign = ((VarItem) this.item1).entry; 28 | Entry a = ((VarItem) this.item2).entry; 29 | Entry b = ((VarItem) this.item3).entry; 30 | 31 | if (a instanceof ConstValueEntry && b instanceof ConstValueEntry) { 32 | Integer aValue = (Integer) ((ConstValueEntry) a).getValue(); 33 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 34 | Integer boolValue = (aValue >= bValue) ? 1 : 0; 35 | ret.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), boolValue)); 36 | } else if (a instanceof ConstValueEntry) { 37 | String bReg = pool.find(b); 38 | Integer aValue = (Integer) ((ConstValueEntry) a).getValue(); 39 | ret.addLine(String.format("sle %s, %s, %d", pool.findNoLoad(toAssign), bReg, aValue)); 40 | } else if (b instanceof ConstValueEntry) { 41 | String aReg = pool.find(a); 42 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 43 | ret.addLine(String.format("sge %s, %s, %d", pool.findNoLoad(toAssign), aReg, bValue)); 44 | } else { 45 | String aReg = pool.find(a); 46 | String bReg = pool.find(b); 47 | ret.addLine(String.format("sge %s, %s, %s", pool.findNoLoad(toAssign), aReg, bReg)); 48 | } 49 | 50 | CodeText.textNLine(ret.dump()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/imcode/imexp/BgtExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import imcode.imitem.VarItem; 5 | import improve.component.regpool.RegPool; 6 | import symbolstruct.CodeText; 7 | 8 | import imcode.imitem.IMItem; 9 | import symbolstruct.entries.ConstValueEntry; 10 | import symbolstruct.entries.Entry; 11 | 12 | public class BgtExp extends IMExp { 13 | protected BgtExp(IMItem item1, IMItem item2, IMItem item3) { 14 | assert item1 instanceof VarItem; 15 | assert item2 instanceof VarItem; 16 | assert item3 instanceof VarItem; 17 | this.item1 = item1; 18 | this.item2 = item2; 19 | this.item3 = item3; 20 | } 21 | 22 | @Override 23 | public void toCode(RegPool pool) { 24 | LineContainer ret = new LineContainer(); 25 | 26 | Entry toAssign = ((VarItem) this.item1).entry; 27 | Entry a = ((VarItem) this.item2).entry; 28 | Entry b = ((VarItem) this.item3).entry; 29 | 30 | if (a instanceof ConstValueEntry && b instanceof ConstValueEntry) { 31 | Integer aValue = (Integer) ((ConstValueEntry) a).getValue(); 32 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 33 | Integer boolValue = (aValue > bValue) ? 1 : 0; 34 | ret.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), boolValue)); 35 | } else if (a instanceof ConstValueEntry) { 36 | String bReg = pool.find(b); 37 | Integer aValue = (Integer) ((ConstValueEntry) a).getValue(); 38 | // ret.addLine(String.format("li %s 0", regStr)); 39 | // ret.addLine(String.format("bge %s, %d, %s", bReg, aValue, tmpLabel)); 40 | // ret.addLine(String.format("li %s, 1", regStr)); 41 | // ret.addLine(tmpLabel + ":"); 42 | // ret.addLine(String.format("add %s, %s, $0", pool.findNoLoad(toAssign), regStr)); 43 | String tmpReg = pool.allocTmpReg(); 44 | ret.addLine(String.format("li %s, %d", tmpReg, aValue)); 45 | ret.addLine(String.format("slt %s, %s, %s", pool.findNoLoad(toAssign), bReg, tmpReg)); 46 | } else if (b instanceof ConstValueEntry) { 47 | String aReg = pool.find(a); 48 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 49 | // ret.addLine(String.format("li %s 0", regStr)); 50 | // ret.addLine(String.format("ble %s, %d, %s", aReg, bValue, tmpLabel)); 51 | // ret.addLine(String.format("li %s, 1", regStr)); 52 | // ret.addLine(tmpLabel + ":"); 53 | // ret.addLine(String.format("add %s, %s, $0", pool.findNoLoad(toAssign), regStr)); 54 | ret.addLine(String.format("sgt %s, %s, %d", pool.findNoLoad(toAssign), aReg, bValue)); 55 | } else { 56 | String aReg = pool.find(a); 57 | String bReg = pool.find(b); 58 | // ret.addLine(String.format("li %s 0", regStr)); 59 | // ret.addLine(String.format("ble %s, %s, %s", aReg, bReg, tmpLabel)); 60 | // ret.addLine(String.format("li %s, 1", regStr)); 61 | // ret.addLine(tmpLabel + ":"); 62 | // ret.addLine(String.format("add %s, %s, $0", pool.findNoLoad(toAssign), regStr)); 63 | ret.addLine(String.format("sgt %s, %s, %s", pool.findNoLoad(toAssign), aReg,bReg)); 64 | } 65 | 66 | CodeText.textNLine(ret.dump()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/imcode/imexp/BneExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import global.Config; 5 | import imcode.imitem.VarItem; 6 | import improve.component.regpool.RegPool; 7 | import symbolstruct.CodeText; 8 | 9 | import imcode.imitem.IMItem; 10 | import symbolstruct.entries.ConstValueEntry; 11 | import symbolstruct.entries.Entry; 12 | 13 | import java.util.Objects; 14 | 15 | /** 16 | * 17 | */ 18 | public class BneExp extends IMExp { 19 | protected BneExp(IMItem item1, IMItem item2, IMItem item3) { 20 | assert item1 instanceof VarItem; 21 | assert item2 instanceof VarItem; 22 | assert item3 instanceof VarItem; 23 | this.item1 = item1; 24 | this.item2 = item2; 25 | this.item3 = item3; 26 | } 27 | 28 | @Override 29 | public void toCode(RegPool pool) { 30 | LineContainer ret = new LineContainer(); 31 | 32 | Entry toAssign = ((VarItem) this.item1).entry; 33 | Entry a = ((VarItem) this.item2).entry; 34 | Entry b = ((VarItem) this.item3).entry; 35 | 36 | if (a instanceof ConstValueEntry && b instanceof ConstValueEntry) { 37 | Integer aValue = (Integer) ((ConstValueEntry) a).getValue(); 38 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 39 | Integer boolValue = (!Objects.equals(aValue, bValue)) ? 1 : 0; 40 | ret.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), boolValue)); 41 | } else if (a instanceof ConstValueEntry) { 42 | String bReg = pool.find(b);; 43 | Integer aValue = (Integer) ((ConstValueEntry) a).getValue(); 44 | ret.addLine(String.format("sne %s, %s, %d", pool.findNoLoad(toAssign), bReg, aValue)); 45 | } else if (b instanceof ConstValueEntry) { 46 | String aReg = pool.find(a); 47 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 48 | ret.addLine(String.format("sne %s, %s, %d", pool.findNoLoad(toAssign), aReg, bValue)); 49 | } else { 50 | String aReg = pool.find(a); 51 | String bReg = pool.find(b); 52 | ret.addLine(String.format("sne %s, %s, %s", pool.findNoLoad(toAssign), aReg, bReg)); 53 | } 54 | 55 | CodeText.textNLine(ret.dump()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/imcode/imexp/CallExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import improve.component.regpool.RegPool; 5 | import symbolstruct.CodeText; 6 | import symbolstruct.FuncRegion; 7 | 8 | import imcode.imitem.FuncItem; 9 | import imcode.imitem.IMItem; 10 | import imcode.imitem.LabelItem; 11 | import symbolstruct.entries.Entry; 12 | 13 | /** 14 | * 调用函数的四元式 15 | */ 16 | public class CallExp extends IMExp { 17 | protected CallExp(IMItem item1) { 18 | assert item1 instanceof FuncItem; 19 | this.item1 = item1; 20 | } 21 | 22 | @Override 23 | public void toCode(RegPool pool) { 24 | Entry func = ((FuncItem) this.item1).entry; 25 | LineContainer c = new LineContainer(); 26 | c.addLine(String.format("jal %s", func.name)); 27 | c.addLine(String.format("nop", func.name)); 28 | CodeText.textNLine(c.dump()); 29 | return; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | String item = ((FuncItem) this.item1).entry.name; 35 | return "call " + item + "()"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/imcode/imexp/ConJumpExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import global.Config; 5 | import imcode.imitem.IntItem; 6 | import improve.component.regpool.RegPool; 7 | import symbolstruct.CodeText; 8 | import symbolstruct.FuncRegion; 9 | 10 | import component.Label; 11 | import imcode.imitem.IMItem; 12 | import imcode.imitem.LabelItem; 13 | import imcode.imitem.VarItem; 14 | import symbolstruct.entries.ConstValueEntry; 15 | import symbolstruct.entries.Entry; 16 | 17 | public class ConJumpExp extends IMExp { 18 | protected ConJumpExp(IMItem label, IMItem conVar) { 19 | assert label instanceof LabelItem; 20 | assert conVar instanceof VarItem; 21 | this.item1 = label; 22 | this.item2 = conVar; 23 | } 24 | 25 | @Override 26 | public void toCode(RegPool pool) { 27 | Label label = ((LabelItem) this.item1).labelName; 28 | 29 | Entry a = ((VarItem) this.item2).entry; 30 | if (a instanceof ConstValueEntry) { 31 | Integer value = (Integer) ((ConstValueEntry) a).getValue(); 32 | if (value == 1) { 33 | CodeText.textNLine(String.format("j %s", label.labelName)); 34 | } 35 | } else { 36 | CodeText.textNLine(String.format("bne $0, %s, %s", pool.find(a), label.labelName)); 37 | } 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | Label label = ((LabelItem) this.item1).labelName; 43 | String con = ((VarItem) this.item2).entry.name; 44 | return "conjump " + label.labelName + " by " + con; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/imcode/imexp/ConNotJumpExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import improve.component.regpool.RegPool; 5 | import symbolstruct.CodeText; 6 | import symbolstruct.FuncRegion; 7 | 8 | import component.Label; 9 | import imcode.imitem.IMItem; 10 | import imcode.imitem.LabelItem; 11 | import imcode.imitem.VarItem; 12 | import symbolstruct.entries.ConstValueEntry; 13 | import symbolstruct.entries.Entry; 14 | 15 | public class ConNotJumpExp extends IMExp { 16 | protected ConNotJumpExp(IMItem label, IMItem conVar) { 17 | assert label instanceof LabelItem; 18 | assert conVar instanceof VarItem; 19 | this.item1 = label; 20 | this.item2 = conVar; 21 | } 22 | 23 | @Override 24 | public void toCode(RegPool pool) { 25 | Label label = ((LabelItem) this.item1).labelName; 26 | 27 | Entry a = ((VarItem) this.item2).entry; 28 | if (a instanceof ConstValueEntry) { 29 | Integer value = (Integer) ((ConstValueEntry) a).getValue(); 30 | if (value == 0) { 31 | CodeText.textNLine(String.format("j %s", label.labelName)); 32 | } 33 | } else { 34 | CodeText.textNLine(String.format("beq $0, %s, %s", pool.find(a), label.labelName)); 35 | } 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | Label label = ((LabelItem) this.item1).labelName; 41 | String con = ((VarItem) this.item2).entry.name; 42 | return "injump " + label.labelName + " by " + con; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/imcode/imexp/DivExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import global.Config; 4 | import improve.component.regpool.RegPool; 5 | 6 | import component.LineContainer; 7 | import imcode.imitem.IMItem; 8 | import imcode.imitem.IntItem; 9 | import imcode.imitem.VarItem; 10 | import symbolstruct.CodeText; 11 | import symbolstruct.entries.ConstValueEntry; 12 | import symbolstruct.entries.Entry; 13 | 14 | public class DivExp extends IMExp { 15 | protected DivExp(IMItem item1, IMItem item2, IMItem item3) { 16 | assert item1 instanceof VarItem; 17 | assert item2 instanceof VarItem; 18 | assert item3 instanceof VarItem; 19 | this.item1 = item1; 20 | this.item2 = item2; 21 | this.item3 = item3; 22 | } 23 | 24 | @Override 25 | public void toCode(RegPool pool) { 26 | LineContainer ret = new LineContainer(); 27 | 28 | Entry toAssign = ((VarItem) this.item1).entry; 29 | Entry a = ((VarItem) this.item2).entry; 30 | Entry b = ((VarItem) this.item3).entry; 31 | 32 | if (a instanceof ConstValueEntry && b instanceof ConstValueEntry) { 33 | ret.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), 34 | ((Integer) ((ConstValueEntry) a).getValue()) / ((Integer) ((ConstValueEntry) b).getValue()))); 35 | } else if (a instanceof ConstValueEntry) { 36 | String regStr = pool.allocTmpReg(); 37 | ret.addLine(String.format("li %s %d", regStr, ((ConstValueEntry) a).getValue())); 38 | ret.addLine(String.format("div %s, %s", regStr, pool.find(b))); 39 | ret.addLine(String.format("mflo %s", pool.findNoLoad(toAssign))); 40 | } else if (b instanceof ConstValueEntry) { 41 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 42 | Integer powerOfTwo = Config.PowerOfTwo(bValue); 43 | if(bValue == 1) { 44 | String aReg = pool.find(a); 45 | ret.addLine(String.format("add %s, %s, $0", pool.findNoLoad(toAssign), aReg)); 46 | } 47 | else if (powerOfTwo != null) { 48 | String tmpReg = pool.allocTmpReg(); 49 | String aReg = pool.find(a); 50 | String assignReg = pool.findNoLoad(toAssign); 51 | String tmpLabel = "templabel" + Config.getTmpNameSed(); 52 | ret.addLine(String.format("add %s, %s, $0", tmpReg, aReg)); 53 | ret.addLine(String.format("sra %s, %s, %d", assignReg, aReg, powerOfTwo)); 54 | ret.addLine(String.format("bgez %s, %s", aReg, tmpLabel)); 55 | ret.addLine(String.format("ori %s, %s, -%d", tmpReg, tmpReg, bValue)); 56 | ret.addLine(String.format("sub %s, %s, -%d", tmpReg, tmpReg, bValue)); 57 | ret.addLine(String.format("beqz %s, %s", tmpReg, tmpLabel)); 58 | ret.addLine(String.format("add %s, %s, 1", assignReg, assignReg)); 59 | ret.addLine(String.format("%s:", tmpLabel)); 60 | } else { 61 | String regStr = pool.allocTmpReg(); 62 | ret.addLine(String.format("li %s %d", regStr, bValue)); 63 | ret.addLine(String.format("div %s, %s", pool.find(a), regStr)); 64 | ret.addLine(String.format("mflo %s", pool.findNoLoad(toAssign))); 65 | } 66 | } else { 67 | ret.addLine(String.format("div %s, %s", pool.find(a), pool.find(b))); 68 | ret.addLine(String.format("mflo %s", pool.findNoLoad(toAssign))); 69 | } 70 | 71 | CodeText.textNLine(ret.dump()); 72 | } 73 | 74 | @Override 75 | public String toString() { 76 | String a = null; 77 | if (this.item2 instanceof IntItem) { 78 | a = String.valueOf(((IntItem) this.item2).intValue); 79 | } else if (this.item2 instanceof VarItem) { 80 | a = ((VarItem) this.item2).entry.name; 81 | } 82 | 83 | String b = null; 84 | if (this.item3 instanceof IntItem) { 85 | b = String.valueOf(((IntItem) this.item3).intValue); 86 | } else if (this.item3 instanceof VarItem) { 87 | b = ((VarItem) this.item3).entry.name; 88 | } 89 | String it = ((VarItem) this.item1).entry.name; 90 | return it + " = " + a + " / " + b; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/imcode/imexp/IMExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import improve.component.regpool.RegPool; 4 | import symbolstruct.FuncRegion; 5 | 6 | import imcode.imitem.IMItem; 7 | import symbolstruct.FuncRegion; 8 | import symbolstruct.Scope; 9 | 10 | public abstract class IMExp { 11 | public IMItem item1; 12 | public IMItem item2; 13 | public IMItem item3; 14 | 15 | public Scope in; 16 | 17 | public abstract void toCode(RegPool pool); 18 | 19 | @Override 20 | public String toString() { 21 | return this.getClass().getSimpleName() + 22 | " " + item1 + 23 | ", " + item2 + 24 | ", " + item3; 25 | } 26 | 27 | public void setIn(Scope in) { 28 | this.in = in; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/imcode/imexp/IMExpType.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp;import symbolstruct.FuncRegion; 2 | 3 | /** 4 | * 四元式类型 5 | */ 6 | public enum IMExpType { 7 | ParaDef, 8 | 9 | AssignByVarAddr, 10 | 11 | AssignByVar, // assign a variable by a variable 12 | AssignByInt, // assign a variable by a variable 13 | AssignByGetInt, // assign a variable by getint 14 | AssignByRet, // assign a variable by func ret 15 | 16 | AssignToAddr, // 向指定地址写入 17 | AssignFromAddr, // 从指定地址读取 18 | 19 | PushPara, // before call a func, we push the required paras into it 20 | Call, // call a func 21 | Return, 22 | 23 | Label, 24 | ConJump, 25 | ConNotJump, 26 | Jump, 27 | 28 | PrintVar, 29 | PrintStr, 30 | 31 | Add, 32 | Sub, 33 | Mul, 34 | Div, 35 | Mod, 36 | 37 | Bgt,Bge,Beq,Bne, 38 | 39 | And, 40 | Or, 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/imcode/imexp/IMFac.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.Label; 4 | import component.narray.NArray; 5 | import component.narray.NPos; 6 | import global.Error; 7 | import imcode.imitem.IMItem; 8 | import imcode.imitem.IMItemFac; 9 | import imcode.imitem.IMItemType; 10 | import imcode.imitem.VarItem; 11 | import symbolstruct.entries.AbsVarEntry; 12 | import symbolstruct.entries.FuncEntry; 13 | import symbolstruct.entries.SpaceEntry; 14 | import symbolstruct.entries.VarEntry; 15 | 16 | public abstract class IMFac { 17 | public static IMExp gen(IMExpType type, Object... items) { 18 | switch (type) { 19 | case ParaDef: 20 | assert items[0] instanceof VarEntry; 21 | return new ParaDefExp(convert(items[0])); 22 | case Beq: 23 | assert items[0] instanceof VarEntry; 24 | assert items[1] != null; 25 | assert items[2] != null; 26 | return new BeqExp(convert(items[0]), convert(items[1]), convert(items[2])); 27 | case Bge: 28 | assert items[0] instanceof VarEntry; 29 | assert items[1] != null; 30 | assert items[2] != null; 31 | return new BgeExp(convert(items[0]), convert(items[1]), convert(items[2])); 32 | case Bgt: 33 | assert items[0] instanceof VarEntry; 34 | assert items[1] != null; 35 | assert items[2] != null; 36 | return new BgtExp(convert(items[0]), convert(items[1]), convert(items[2])); 37 | case Bne: 38 | assert items[0] instanceof VarEntry; 39 | assert items[1] != null; 40 | assert items[2] != null; 41 | return new BneExp(convert(items[0]), convert(items[1]), convert(items[2])); 42 | case ConJump: 43 | assert items[0] instanceof Label; 44 | assert items[1] instanceof VarEntry; 45 | return new ConJumpExp(convert(items[0]), convert(items[1])); 46 | case ConNotJump: 47 | assert items[0] instanceof Label; 48 | assert items[1] instanceof VarEntry; 49 | return new ConNotJumpExp(convert(items[0]), convert(items[1])); 50 | case PushPara: 51 | assert items[0] instanceof AbsVarEntry; 52 | assert items[0] instanceof Integer; 53 | return new PushParaExp(convert(items[0]), convert(items[1])); 54 | case Call: 55 | assert items[0] instanceof FuncEntry; 56 | return new CallExp(convert(items[0])); 57 | case Return: 58 | if (items == null) { 59 | return new ReturnExp(null); 60 | } else { 61 | assert items[0] instanceof VarEntry; 62 | return new ReturnExp(convert(items[0])); 63 | } 64 | case AssignByRet: 65 | assert items[0] instanceof VarEntry; 66 | return new AssignByRetExp(convert(items[0])); 67 | case Jump: 68 | assert items[0] instanceof Label; 69 | return new JumpExp(convert(items[0])); 70 | case Label: 71 | assert items[0] instanceof Label; 72 | return new LabelExp(convert(items[0])); 73 | case AssignByVarAddr: 74 | assert items[0] instanceof AbsVarEntry; 75 | assert items[1] instanceof SpaceEntry; 76 | return new AssignByVarAddrExp(convert(items[0]), convert(items[1])); 77 | case AssignByVar: 78 | assert items[0] instanceof VarEntry; 79 | assert items[1] instanceof VarEntry; 80 | return new AssignByVarExp(convert(items[0]), convert(items[1])); 81 | case AssignByGetInt: 82 | assert items[0] instanceof VarEntry; 83 | return new AssignByGetInt(convert(items[0])); 84 | case AssignToAddr: 85 | assert items[0] instanceof VarEntry; 86 | assert items[1] instanceof VarEntry; 87 | return new AssignToAddrExp(convert(items[0]), convert(items[1])); 88 | case AssignFromAddr: 89 | assert items[0] instanceof VarEntry; 90 | assert items[1] instanceof VarEntry; 91 | return new AssignFromAddrExp(convert(items[0]), convert(items[1])); 92 | case PrintVar: 93 | assert items[0] instanceof VarEntry; 94 | return new PrintVarExp(convert(items[0])); 95 | case PrintStr: 96 | assert items[0] instanceof String; 97 | return new PrintStrExp(convert(items[0])); 98 | case Add: 99 | assert items[0] instanceof AbsVarEntry; // 因为可能直接将ArrayEntry+4从而获得ArrayEntry[1]元素的地址 100 | assert items[1] != null; 101 | assert items[2] != null; 102 | return new AddExp(convert(items[0]), convert(items[1]), convert(items[2])); 103 | case Div: 104 | assert items[0] instanceof VarEntry; 105 | assert items[1] != null; 106 | assert items[2] != null; 107 | return new DivExp(convert(items[0]), convert(items[1]), convert(items[2])); 108 | case Mod: 109 | assert items[0] instanceof VarEntry; 110 | assert items[1] != null; 111 | assert items[2] != null; 112 | return new ModExp(convert(items[0]), convert(items[1]), convert(items[2])); 113 | case Mul: 114 | assert items[0] instanceof VarEntry; 115 | assert items[1] != null; 116 | assert items[2] != null; 117 | return new MulExp(convert(items[0]), convert(items[1]), convert(items[2])); 118 | case Sub: 119 | assert items[0] instanceof AbsVarEntry; 120 | assert items[1] != null; 121 | assert items[2] != null; 122 | return new SubExp(convert(items[0]), convert(items[1]), convert(items[2])); 123 | default: 124 | Error.warning("An Unknown Type Of IMExp created!"); 125 | return null; 126 | } 127 | } 128 | 129 | /** 130 | * 将Object对象转变为对应的操作数对象IMItem 131 | * Integer -> Int 常数 132 | * AbsVarEntry -> Var 变量(普通变量和数组变量) 133 | * ArrayList -> Array 数组值(每个数组元素都是一个IMItem) 134 | * 135 | * @param o 需要转变的对象 136 | * @return 转变后的操作数对象 137 | */ 138 | private static IMItem convert(Object o) { 139 | if (o instanceof Integer) { 140 | return IMItemFac.gen(IMItemType.Int, o); 141 | } else if (o instanceof FuncEntry) { 142 | return IMItemFac.gen(IMItemType.Func, o); 143 | } else if (o instanceof NArray) { 144 | return IMItemFac.gen(IMItemType.Array, o); 145 | } else if (o instanceof NPos) { 146 | return IMItemFac.gen(IMItemType.NPos, o); 147 | } else if (o instanceof String) { 148 | return IMItemFac.gen(IMItemType.Str, o); 149 | } else if (o instanceof SpaceEntry) { 150 | return IMItemFac.gen(IMItemType.Space, o); 151 | } else if (o instanceof AbsVarEntry) { 152 | return IMItemFac.gen(IMItemType.Var, o); 153 | } else if (o instanceof Label) { 154 | return IMItemFac.gen(IMItemType.Label, o); 155 | } else { 156 | Error.warning("Unsupported type of Object to covert"); 157 | return null; 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/imcode/imexp/JumpExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import imcode.imitem.VarItem; 5 | import improve.component.regpool.RegPool; 6 | import symbolstruct.CodeText; 7 | import symbolstruct.FuncRegion; 8 | 9 | import component.Label; 10 | import imcode.imitem.IMItem; 11 | import imcode.imitem.LabelItem; 12 | import symbolstruct.entries.Entry; 13 | 14 | /** 15 | * 跳转语句 16 | */ 17 | public class JumpExp extends IMExp { 18 | protected JumpExp(IMItem item1) { 19 | assert item1 instanceof LabelItem; 20 | this.item1 = item1; 21 | } 22 | 23 | @Override 24 | public void toCode(RegPool pool) { 25 | LineContainer ret = new LineContainer(); 26 | Label label = ((LabelItem) this.item1).labelName; 27 | 28 | ret.addLine("j " + label.labelName); 29 | 30 | CodeText.textNLine(ret.dump()); 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | Label label = ((LabelItem) this.item1).labelName; 36 | return "jump " + label.labelName; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/imcode/imexp/LabelExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import imcode.imitem.VarItem; 5 | import improve.component.regpool.RegPool; 6 | import symbolstruct.CodeText; 7 | import symbolstruct.FuncRegion; 8 | 9 | import component.Label; 10 | import imcode.imitem.IMItem; 11 | import imcode.imitem.LabelItem; 12 | import symbolstruct.entries.Entry; 13 | 14 | public class LabelExp extends IMExp { 15 | protected LabelExp(IMItem item1) { 16 | assert item1 instanceof LabelItem; 17 | this.item1 = item1; 18 | } 19 | 20 | @Override 21 | public void toCode(RegPool pool) { 22 | LineContainer ret = new LineContainer(); 23 | Label label = ((LabelItem) this.item1).labelName; 24 | 25 | ret.addLine(label.labelName + ":"); 26 | 27 | CodeText.textNLine(ret.dump()); 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | Label label = ((LabelItem) this.item1).labelName; 33 | return label.labelName + ":"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/imcode/imexp/ModExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import improve.component.regpool.RegPool; 4 | 5 | import component.LineContainer; 6 | import imcode.imitem.IMItem; 7 | import imcode.imitem.IntItem; 8 | import imcode.imitem.VarItem; 9 | import symbolstruct.CodeText; 10 | import symbolstruct.entries.ConstValueEntry; 11 | import symbolstruct.entries.Entry; 12 | 13 | public class ModExp extends IMExp { 14 | protected ModExp(IMItem item1, IMItem item2, IMItem item3) { 15 | assert item1 instanceof VarItem; 16 | assert item2 instanceof VarItem; 17 | assert item3 instanceof VarItem; 18 | this.item1 = item1; 19 | this.item2 = item2; 20 | this.item3 = item3; 21 | } 22 | 23 | @Override 24 | public void toCode(RegPool pool) { 25 | LineContainer ret = new LineContainer(); 26 | 27 | Entry toAssign = ((VarItem) this.item1).entry; 28 | Entry a = ((VarItem) this.item2).entry; 29 | Entry b = ((VarItem) this.item3).entry; 30 | 31 | if (a instanceof ConstValueEntry && b instanceof ConstValueEntry) { 32 | ret.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), 33 | ((Integer) ((ConstValueEntry) a).getValue()) % ((Integer) ((ConstValueEntry) b).getValue()))); 34 | } else if (a instanceof ConstValueEntry) { 35 | String regStr = pool.allocTmpReg(); 36 | ret.addLine(String.format("li %s %d", regStr, ((ConstValueEntry) a).getValue())); 37 | ret.addLine(String.format("div %s, %s", regStr, pool.find(b))); 38 | ret.addLine(String.format("mfhi %s", pool.findNoLoad(toAssign))); 39 | } else if (b instanceof ConstValueEntry) { 40 | String regStr = pool.allocTmpReg(); 41 | ret.addLine(String.format("li %s %d", regStr, ((ConstValueEntry) b).getValue())); 42 | ret.addLine(String.format("div %s, %s", pool.find(a), regStr)); 43 | ret.addLine(String.format("mfhi %s", pool.findNoLoad(toAssign))); 44 | } else { 45 | ret.addLine(String.format("div %s, %s", pool.find(a), pool.find(b))); 46 | ret.addLine(String.format("mfhi %s", pool.findNoLoad(toAssign))); 47 | } 48 | 49 | CodeText.textNLine(ret.dump()); 50 | } 51 | @Override 52 | public String toString() { 53 | String a = null; 54 | if (this.item2 instanceof IntItem) { 55 | a = String.valueOf(((IntItem) this.item2).intValue); 56 | } else if (this.item2 instanceof VarItem) { 57 | a = ((VarItem) this.item2).entry.name; 58 | } 59 | 60 | String b = null; 61 | if (this.item3 instanceof IntItem) { 62 | b = String.valueOf(((IntItem) this.item3).intValue); 63 | } else if (this.item3 instanceof VarItem) { 64 | b = ((VarItem) this.item3).entry.name; 65 | } 66 | String it = ((VarItem) this.item1).entry.name; 67 | return it + " = " + a + " % " + b; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/imcode/imexp/MulExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import global.Config; 4 | import improve.component.regpool.RegPool; 5 | 6 | import component.LineContainer; 7 | import imcode.imitem.IMItem; 8 | import imcode.imitem.IntItem; 9 | import imcode.imitem.VarItem; 10 | import symbolstruct.CodeText; 11 | import symbolstruct.entries.ConstValueEntry; 12 | import symbolstruct.entries.Entry; 13 | 14 | public class MulExp extends IMExp { 15 | protected MulExp(IMItem item1, IMItem item2, IMItem item3) { 16 | assert item1 instanceof VarItem; 17 | assert item2 instanceof VarItem; 18 | assert item3 instanceof VarItem; 19 | this.item1 = item1; 20 | this.item2 = item2; 21 | this.item3 = item3; 22 | } 23 | 24 | @Override 25 | public void toCode(RegPool pool) { 26 | LineContainer ret = new LineContainer(); 27 | 28 | Entry toAssign = ((VarItem) this.item1).entry; 29 | Entry a = ((VarItem) this.item2).entry; 30 | Entry b = ((VarItem) this.item3).entry; 31 | 32 | if (a instanceof ConstValueEntry && b instanceof ConstValueEntry) { 33 | ret.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), 34 | ((Integer) ((ConstValueEntry) a).getValue()) * ((Integer) ((ConstValueEntry) b).getValue()))); 35 | } else if (a instanceof ConstValueEntry) { 36 | String bReg = pool.find(b); 37 | ret.addLine(String.format("mul %s, %s, %d", pool.findNoLoad(toAssign), bReg, ((ConstValueEntry) a).getValue())); 38 | } else if (b instanceof ConstValueEntry) { 39 | Integer bValue = (Integer) ((ConstValueEntry) b).getValue(); 40 | Integer powerOfTwo = Config.PowerOfTwo(bValue); 41 | String aReg = pool.find(a); 42 | if (bValue == 1) { 43 | ret.addLine(String.format("add %s, %s, $0", pool.findNoLoad(toAssign), aReg)); 44 | } else if (powerOfTwo != null) { 45 | ret.addLine(String.format("sll %s, %s, %d", pool.findNoLoad(toAssign), aReg, powerOfTwo)); 46 | } else { 47 | ret.addLine(String.format("mul %s, %s, %d", pool.findNoLoad(toAssign), aReg, bValue)); 48 | } 49 | } else { 50 | String aReg = pool.find(a); 51 | String bReg = pool.find(b); 52 | ret.addLine(String.format("mul %s, %s, %s", pool.findNoLoad(toAssign), aReg, bReg)); 53 | } 54 | 55 | CodeText.textNLine(ret.dump()); 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | String a = null; 61 | if (this.item2 instanceof IntItem) { 62 | a = String.valueOf(((IntItem) this.item2).intValue); 63 | } else if (this.item2 instanceof VarItem) { 64 | a = ((VarItem) this.item2).entry.name; 65 | } 66 | 67 | String b = null; 68 | if (this.item3 instanceof IntItem) { 69 | b = String.valueOf(((IntItem) this.item3).intValue); 70 | } else if (this.item3 instanceof VarItem) { 71 | b = ((VarItem) this.item3).entry.name; 72 | } 73 | String it = ((VarItem) this.item1).entry.name; 74 | return it + " = " + a + " * " + b; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/imcode/imexp/OPTBranchExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.Label; 4 | import imcode.imitem.LabelItem; 5 | import imcode.imitem.VarItem; 6 | import improve.component.regpool.RegPool; 7 | import symbolstruct.CodeText; 8 | import symbolstruct.entries.ConstValueEntry; 9 | import symbolstruct.entries.Entry; 10 | 11 | public class OPTBranchExp extends IMExp { 12 | private IMExp calExp; 13 | private IMExp jumpExp; 14 | 15 | public OPTBranchExp(IMExp calExp, IMExp jumpExp) { 16 | assert calExp instanceof BgeExp || calExp instanceof BgtExp || calExp instanceof BeqExp || calExp instanceof BneExp; 17 | assert jumpExp instanceof ConJumpExp || jumpExp instanceof ConNotJumpExp; 18 | this.calExp = calExp; 19 | this.jumpExp = jumpExp; 20 | 21 | this.item1 = jumpExp.item1; 22 | this.item2 = calExp.item2; 23 | this.item3 = calExp.item3; 24 | } 25 | 26 | @Override 27 | public void toCode(RegPool pool) { 28 | Entry calA = ((VarItem) calExp.item2).entry; 29 | Entry calB = ((VarItem) calExp.item3).entry; 30 | Label label = ((LabelItem) jumpExp.item1).labelName; 31 | if (jumpExp instanceof ConJumpExp) { 32 | if (calExp instanceof BgtExp) { 33 | if (calA instanceof ConstValueEntry && calB instanceof ConstValueEntry) { 34 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 35 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 36 | if (aValue > bValue) { 37 | CodeText.textNLine(String.format("j %s", label.labelName)); 38 | } 39 | } else if (calA instanceof ConstValueEntry) { 40 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 41 | CodeText.textNLine(String.format("blt %s, %d, %s", pool.find(calB), aValue, label.labelName)); 42 | } else if (calB instanceof ConstValueEntry) { 43 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 44 | CodeText.textNLine(String.format("bgt %s, %d, %s", pool.find(calA), bValue, label.labelName)); 45 | } else { 46 | CodeText.textNLine(String.format("bgt %s, %s, %s", pool.find(calA), pool.find(calB), label.labelName)); 47 | } 48 | } else if (calExp instanceof BgeExp) { 49 | if (calA instanceof ConstValueEntry && calB instanceof ConstValueEntry) { 50 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 51 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 52 | if (aValue >= bValue) { 53 | CodeText.textNLine(String.format("j %s", label.labelName)); 54 | } 55 | } else if (calA instanceof ConstValueEntry) { 56 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 57 | CodeText.textNLine(String.format("ble %s, %d, %s", pool.find(calB), aValue, label.labelName)); 58 | } else if (calB instanceof ConstValueEntry) { 59 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 60 | CodeText.textNLine(String.format("bge %s, %d, %s", pool.find(calA), bValue, label.labelName)); 61 | } else { 62 | CodeText.textNLine(String.format("bge %s, %s, %s", pool.find(calA), pool.find(calB), label.labelName)); 63 | } 64 | } else if (calExp instanceof BeqExp) { 65 | if (calA instanceof ConstValueEntry && calB instanceof ConstValueEntry) { 66 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 67 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 68 | if (aValue == bValue) { 69 | CodeText.textNLine(String.format("j %s", label.labelName)); 70 | } 71 | } else if (calA instanceof ConstValueEntry) { 72 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 73 | CodeText.textNLine(String.format("beq %s, %d, %s", pool.find(calB), aValue, label.labelName)); 74 | } else if (calB instanceof ConstValueEntry) { 75 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 76 | CodeText.textNLine(String.format("beq %s, %d, %s", pool.find(calA), bValue, label.labelName)); 77 | } else { 78 | CodeText.textNLine(String.format("beq %s, %s, %s", pool.find(calA), pool.find(calB), label.labelName)); 79 | } 80 | } else if (calExp instanceof BneExp) { 81 | if (calA instanceof ConstValueEntry && calB instanceof ConstValueEntry) { 82 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 83 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 84 | if (aValue != bValue) { 85 | CodeText.textNLine(String.format("j %s", label.labelName)); 86 | } 87 | } else if (calA instanceof ConstValueEntry) { 88 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 89 | CodeText.textNLine(String.format("bne %s, %d, %s", pool.find(calB), aValue, label.labelName)); 90 | } else if (calB instanceof ConstValueEntry) { 91 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 92 | CodeText.textNLine(String.format("bne %s, %d, %s", pool.find(calA), bValue, label.labelName)); 93 | } else { 94 | CodeText.textNLine(String.format("bne %s, %s, %s", pool.find(calA), pool.find(calB), label.labelName)); 95 | } 96 | } 97 | } else if (jumpExp instanceof ConNotJumpExp) { 98 | if (calExp instanceof BgtExp) { 99 | if (calA instanceof ConstValueEntry && calB instanceof ConstValueEntry) { 100 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 101 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 102 | if (aValue <= bValue) { 103 | CodeText.textNLine(String.format("j %s", label.labelName)); 104 | } 105 | } else if (calA instanceof ConstValueEntry) { 106 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 107 | CodeText.textNLine(String.format("bge %s, %d, %s", pool.find(calB), aValue, label.labelName)); 108 | } else if (calB instanceof ConstValueEntry) { 109 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 110 | CodeText.textNLine(String.format("ble %s, %d, %s", pool.find(calA), bValue, label.labelName)); 111 | } else { 112 | CodeText.textNLine(String.format("ble %s, %s, %s", pool.find(calA), pool.find(calB), label.labelName)); 113 | } 114 | } else if (calExp instanceof BgeExp) { 115 | if (calA instanceof ConstValueEntry && calB instanceof ConstValueEntry) { 116 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 117 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 118 | if (aValue < bValue) { 119 | CodeText.textNLine(String.format("j %s", label.labelName)); 120 | } 121 | } else if (calA instanceof ConstValueEntry) { 122 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 123 | CodeText.textNLine(String.format("bgt %s, %d, %s", pool.find(calB), aValue, label.labelName)); 124 | } else if (calB instanceof ConstValueEntry) { 125 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 126 | CodeText.textNLine(String.format("blt %s, %d, %s", pool.find(calA), bValue, label.labelName)); 127 | } else { 128 | CodeText.textNLine(String.format("blt %s, %s, %s", pool.find(calA), pool.find(calB), label.labelName)); 129 | } 130 | } else if (calExp instanceof BeqExp) { 131 | if (calA instanceof ConstValueEntry && calB instanceof ConstValueEntry) { 132 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 133 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 134 | if (aValue != bValue) { 135 | CodeText.textNLine(String.format("j %s", label.labelName)); 136 | } 137 | } else if (calA instanceof ConstValueEntry) { 138 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 139 | CodeText.textNLine(String.format("bne %s, %d, %s", pool.find(calB), aValue, label.labelName)); 140 | } else if (calB instanceof ConstValueEntry) { 141 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 142 | CodeText.textNLine(String.format("bne %s, %d, %s", pool.find(calA), bValue, label.labelName)); 143 | } else { 144 | CodeText.textNLine(String.format("bne %s, %s, %s", pool.find(calA), pool.find(calB), label.labelName)); 145 | } 146 | } else if (calExp instanceof BneExp) { 147 | if (calA instanceof ConstValueEntry && calB instanceof ConstValueEntry) { 148 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 149 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 150 | if (aValue == bValue) { 151 | CodeText.textNLine(String.format("j %s", label.labelName)); 152 | } 153 | } else if (calA instanceof ConstValueEntry) { 154 | Integer aValue = (Integer) ((ConstValueEntry) calA).getValue(); 155 | CodeText.textNLine(String.format("beq %s, %d, %s", pool.find(calB), aValue, label.labelName)); 156 | } else if (calB instanceof ConstValueEntry) { 157 | Integer bValue = (Integer) ((ConstValueEntry) calB).getValue(); 158 | CodeText.textNLine(String.format("beq %s, %d, %s", pool.find(calA), bValue, label.labelName)); 159 | } else { 160 | CodeText.textNLine(String.format("beq %s, %s, %s", pool.find(calA), pool.find(calB), label.labelName)); 161 | } 162 | } 163 | } 164 | } 165 | 166 | @Override 167 | public String toString() { 168 | return jumpExp.getClass().getSimpleName() + " " + calExp.getClass().getSimpleName() + " " 169 | + ((VarItem)item2).entry.name + " " 170 | + ((VarItem)item3).entry.name + " " 171 | + ((LabelItem)item1).labelName.labelName; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/imcode/imexp/ParaDefExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import imcode.imitem.IMItem; 4 | import imcode.imitem.VarItem; 5 | import improve.component.regpool.RegPool; 6 | import symbolstruct.FuncRegion; 7 | 8 | public class ParaDefExp extends IMExp { 9 | public ParaDefExp(IMItem var) { 10 | assert var instanceof VarItem; 11 | this.item1 = var; 12 | } 13 | 14 | @Override 15 | public void toCode(RegPool pool) { 16 | return; 17 | } 18 | 19 | @Override 20 | public String toString() { 21 | return "import " + ((VarItem) this.item1).entry.name; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/imcode/imexp/PrintStrExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import improve.component.regpool.RegPool; 5 | import symbolstruct.CodeText; 6 | import symbolstruct.FuncRegion; 7 | 8 | import imcode.imitem.IMItem; 9 | import imcode.imitem.StrItem; 10 | 11 | public class PrintStrExp extends IMExp { 12 | protected PrintStrExp(IMItem strItem) { 13 | assert strItem instanceof StrItem; 14 | this.item2 = strItem; 15 | } 16 | 17 | @Override 18 | public void toCode(RegPool pool) { 19 | LineContainer c = new LineContainer(); 20 | String marker = ((StrItem) this.item2).strValue; 21 | c.addLine(String.format("la $a0, %s", marker)); 22 | c.addLine(String.format("li $v0, 4")); 23 | c.addLine(String.format("syscall")); 24 | CodeText.textNLine(c.dump()); 25 | return; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | String top = ((StrItem) this.item2).strValue; 31 | return "print \"" + top + "\""; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/imcode/imexp/PrintVarExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import improve.component.regpool.RegPool; 5 | import symbolstruct.CodeText; 6 | import symbolstruct.FuncRegion; 7 | 8 | import imcode.imitem.IMItem; 9 | import imcode.imitem.StrItem; 10 | import imcode.imitem.VarItem; 11 | import symbolstruct.entries.ConstValueEntry; 12 | import symbolstruct.entries.Entry; 13 | 14 | /** 15 | * 打印一个变量操作数或一个字符串操作数 16 | */ 17 | public class PrintVarExp extends IMExp { 18 | protected PrintVarExp(IMItem item) { 19 | assert item instanceof VarItem; 20 | this.item2 = item; 21 | } 22 | 23 | @Override 24 | public void toCode(RegPool pool) { 25 | LineContainer ret = new LineContainer(); 26 | Entry entry = ((VarItem) this.item2).entry; 27 | if (entry instanceof ConstValueEntry) { 28 | ret.addLine(String.format("addi $a0, $0, %d", ((ConstValueEntry) entry).getValue())); 29 | } else { 30 | ret.addLine(String.format("add $a0, %s, $0", pool.find(entry))); 31 | } 32 | ret.addLine(String.format("li $v0, 1")); 33 | ret.addLine(String.format("syscall")); 34 | CodeText.textNLine(ret.dump()); 35 | return; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | String it = ((VarItem) this.item2).entry.name; 41 | return "print " + it; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/imcode/imexp/PushParaExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import imcode.imitem.IntItem; 5 | import improve.component.regpool.RegPool; 6 | import symbolstruct.CodeText; 7 | 8 | import imcode.imitem.IMItem; 9 | import imcode.imitem.VarItem; 10 | import symbolstruct.entries.ConstValueEntry; 11 | import symbolstruct.entries.Entry; 12 | 13 | /** 14 | * 将参数押入函数的参数栈 15 | * 通常在CallExp前使用, 16 | * 用于准备函数所需的参数 17 | */ 18 | public class PushParaExp extends IMExp { 19 | protected PushParaExp(IMItem item, IMItem counter) { 20 | assert item instanceof VarItem; 21 | assert counter instanceof IntItem; 22 | this.item2 = item; 23 | this.item3 = counter; 24 | } 25 | 26 | @Override 27 | public void toCode(RegPool pool) { 28 | LineContainer c = new LineContainer(); 29 | 30 | Entry var = ((VarItem) this.item2).entry; 31 | Integer off = ((IntItem) this.item3).intValue; 32 | 33 | if (var instanceof ConstValueEntry) { 34 | String regStr = pool.allocTmpReg(); 35 | c.addLine(String.format("li %s, %d", regStr, ((ConstValueEntry) var).getValue())); 36 | c.addLine(String.format("sw %s, -%d($sp)", regStr, off * 4)); 37 | } else { 38 | c.addLine(String.format("sw %s, -%d($sp)", pool.find(var), off * 4)); 39 | } 40 | 41 | CodeText.textNLine(c.dump()); 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | String it = ((VarItem) this.item2).entry.name; 47 | return "push " + it; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/imcode/imexp/ReturnExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import component.LineContainer; 4 | import improve.component.regpool.RegPool; 5 | import symbolstruct.CodeText; 6 | import symbolstruct.FuncRegion; 7 | 8 | import imcode.imitem.IMItem; 9 | import imcode.imitem.VarItem; 10 | import symbolstruct.entries.ConstValueEntry; 11 | import symbolstruct.entries.Entry; 12 | 13 | public class ReturnExp extends IMExp { 14 | protected ReturnExp(IMItem var) { 15 | assert var instanceof VarItem || var == null; 16 | this.item2 = var; 17 | } 18 | 19 | @Override 20 | public void toCode(RegPool pool) { 21 | LineContainer c = new LineContainer(); 22 | 23 | if (item2 != null) { 24 | Entry toa = ((VarItem) this.item2).entry; 25 | if (toa instanceof ConstValueEntry) { 26 | c.addLine(String.format("addi $v0, $0, %d", ((ConstValueEntry) toa).getValue())); 27 | } else { 28 | c.addLine(String.format("add $v0, $0, %s", pool.find(toa))); 29 | } 30 | } 31 | 32 | c.addLine("# ret and restore the frame"); 33 | c.addLine(String.format("lw $ra, %d($sp)", pool.getFrame().offsetRA)); 34 | c.addLine(String.format("addiu $sp, $sp, %d", pool.getFrame().size)); 35 | c.addLine(String.format("jr $ra")); 36 | // 恢复函数栈帧并返回指定地址 37 | 38 | CodeText.textNLine(c.dump()); 39 | return; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | if (item2 != null) { 45 | String ret = ((VarItem) this.item2).entry.name; 46 | return "return " + ret; 47 | } else { 48 | return "return;"; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/imcode/imexp/SubExp.java: -------------------------------------------------------------------------------- 1 | package imcode.imexp; 2 | 3 | import improve.component.regpool.RegPool; 4 | import symbolstruct.FuncRegion; 5 | 6 | import component.LineContainer; 7 | import imcode.imitem.IMItem; 8 | import imcode.imitem.IntItem; 9 | import imcode.imitem.VarItem; 10 | import symbolstruct.CodeText; 11 | import symbolstruct.entries.ConstValueEntry; 12 | import symbolstruct.entries.Entry; 13 | 14 | public class SubExp extends IMExp { 15 | protected SubExp(IMItem item1, IMItem item2, IMItem item3) { 16 | assert item1 instanceof VarItem; 17 | assert item2 != null; 18 | assert item3 != null; 19 | this.item1 = item1; 20 | this.item2 = item2; 21 | this.item3 = item3; 22 | } 23 | 24 | @Override 25 | public void toCode(RegPool pool) { 26 | LineContainer ret = new LineContainer(); 27 | 28 | Entry a = ((VarItem) this.item2).entry; 29 | Entry b = ((VarItem) this.item3).entry; 30 | Entry toAssign = ((VarItem) this.item1).entry; 31 | 32 | if (a instanceof ConstValueEntry && b instanceof ConstValueEntry) { 33 | ret.addLine(String.format("li %s, %d", pool.findNoLoad(toAssign), 34 | ((Integer) ((ConstValueEntry) a).getValue()) - ((Integer) ((ConstValueEntry) b).getValue()))); 35 | } else if (a instanceof ConstValueEntry) { 36 | String bReg = pool.find(b); 37 | ret.addLine(String.format("subi %s, %s, %d", 38 | pool.findNoLoad(toAssign), bReg, ((ConstValueEntry) a).getValue())); 39 | ret.addLine(String.format("sub %s, $0, %s", pool.findNoLoad(toAssign), pool.findNoLoad(toAssign))); 40 | } else if (b instanceof ConstValueEntry) { 41 | String aReg = pool.find(a); 42 | ret.addLine(String.format("subi %s, %s, %d", 43 | pool.findNoLoad(toAssign), aReg, ((ConstValueEntry) b).getValue())); 44 | } else { 45 | String aReg = pool.find(a); 46 | String bReg = pool.find(b); 47 | ret.addLine(String.format("sub %s, %s, %s", pool.findNoLoad(toAssign), aReg, bReg)); 48 | } 49 | 50 | CodeText.textNLine(ret.dump()); 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | String a = null; 56 | if (this.item2 instanceof IntItem) { 57 | a = String.valueOf(((IntItem) this.item2).intValue); 58 | } else if (this.item2 instanceof VarItem) { 59 | a = ((VarItem) this.item2).entry.name; 60 | } 61 | 62 | String b = null; 63 | if (this.item3 instanceof IntItem) { 64 | b = String.valueOf(((IntItem) this.item3).intValue); 65 | } else if (this.item3 instanceof VarItem) { 66 | b = ((VarItem) this.item3).entry.name; 67 | } 68 | String it = ((VarItem) this.item1).entry.name; 69 | return it + " = " + a + " - " + b; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/imcode/imitem/FuncItem.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | import component.datatype.Datatype; 4 | import symbolstruct.entries.FuncEntry; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Objects; 8 | 9 | public class FuncItem extends IMItem { 10 | public final FuncEntry entry; 11 | 12 | protected FuncItem(Object entry) { 13 | assert entry instanceof FuncEntry; 14 | this.entry = (FuncEntry) entry; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return this.entry.name + "()"; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | return false; 25 | } 26 | 27 | @Override 28 | public int hashCode() { 29 | return Objects.hash(entry); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/imcode/imitem/IMItem.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | public abstract class IMItem { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/imcode/imitem/IMItemFac.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | import global.Error; 4 | 5 | public class IMItemFac { 6 | /** 7 | * 类型和初始化对象的对应关系: 8 | * Int -> 数值 Integer 9 | * Str -> 字符串值 String 10 | * Var -> 符号项 VarEntry 11 | * Func -> 符号项 FuncEntry 12 | * ArrayInit->基本类型DataType 具体数值ArrayList 13 | * 14 | * @param type 需要的操作数类型 15 | * @param objs 传入的初始化对象 16 | * @return 生成的操作数对象IMItem 17 | */ 18 | public static IMItem gen(IMItemType type, Object... objs) { 19 | switch (type) { 20 | case Int: 21 | return new IntItem(objs[0]); 22 | case Str: 23 | return new StrItem(objs[0]); 24 | case Var: 25 | return new VarItem(objs[0]); 26 | case Func: 27 | return new FuncItem(objs[0]); 28 | case Label: 29 | return new LabelItem(objs[0]); 30 | case NPos: 31 | return new PosItem(objs[0]); 32 | case Space: 33 | return new SpaceItem(objs[0]); 34 | default: 35 | Error.warning("Unknown type IMItem is created in IMItemFac"); 36 | return null; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/imcode/imitem/IMItemType.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | /** 4 | * 四元式的操作数类型 5 | */ 6 | public enum IMItemType { 7 | Var, // 变量类型 8 | Func, // 函数类型 9 | Str, // 字符串类型 10 | Int, // 常数 11 | Label, 12 | Array, 13 | NPos, // 数组中元素位置 14 | Space, // 空间元素,即指代栈上的一段空间 15 | } 16 | -------------------------------------------------------------------------------- /src/imcode/imitem/IntItem.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | import java.util.Objects; 4 | 5 | public class IntItem extends IMItem{ 6 | public final Integer intValue; 7 | 8 | protected IntItem(Object intValue) { 9 | assert intValue instanceof Integer; 10 | this.intValue = (Integer) intValue; 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return String.valueOf(this.intValue); 16 | } 17 | 18 | @Override 19 | public boolean equals(Object o) { 20 | if (this == o) return true; 21 | if (o == null || getClass() != o.getClass()) return false; 22 | IntItem intItem = (IntItem) o; 23 | return Objects.equals(intValue, intItem.intValue); 24 | } 25 | 26 | @Override 27 | public int hashCode() { 28 | return Objects.hash(intValue); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/imcode/imitem/LabelItem.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | import component.Label; 4 | 5 | import java.util.Objects; 6 | 7 | public class LabelItem extends IMItem { 8 | public final Label labelName; 9 | 10 | protected LabelItem(Object name) { 11 | assert name instanceof Label; 12 | this.labelName = (Label) name; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return "#label-"+this.labelName+":"; 18 | } 19 | 20 | @Override 21 | public boolean equals(Object o) { 22 | return false; 23 | } 24 | 25 | @Override 26 | public int hashCode() { 27 | return Objects.hash(labelName); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/imcode/imitem/PosItem.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | 4 | import component.narray.NPos; 5 | 6 | import java.util.Objects; 7 | 8 | public class PosItem extends IMItem{ 9 | public final NPos value; 10 | protected PosItem(Object npos){ 11 | assert npos instanceof NPos; 12 | this.value = (NPos) npos; 13 | } 14 | 15 | @Override 16 | public boolean equals(Object o) { 17 | return false; 18 | } 19 | 20 | @Override 21 | public int hashCode() { 22 | return Objects.hash(value); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/imcode/imitem/SpaceItem.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | import symbolstruct.entries.AbsVarEntry; 4 | import symbolstruct.entries.SpaceEntry; 5 | 6 | import java.util.Objects; 7 | 8 | public class SpaceItem extends IMItem { 9 | public final SpaceEntry entry; 10 | 11 | protected SpaceItem(Object entry) { 12 | assert entry instanceof AbsVarEntry; 13 | this.entry = (SpaceEntry) entry; 14 | } 15 | 16 | @Override 17 | public String toString() { 18 | return "SPACE[" + entry.name + "]"; 19 | } 20 | 21 | @Override 22 | public boolean equals(Object o) { 23 | return false; 24 | } 25 | 26 | @Override 27 | public int hashCode() { 28 | return Objects.hash(entry); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/imcode/imitem/StrItem.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | import java.util.Objects; 4 | 5 | public class StrItem extends IMItem{ 6 | public final String strValue; 7 | 8 | protected StrItem(Object strValue) { 9 | assert strValue instanceof String; 10 | this.strValue = (String) strValue; 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return this.strValue; 16 | } 17 | 18 | @Override 19 | public boolean equals(Object o) { 20 | if (this == o) return true; 21 | if (o == null || getClass() != o.getClass()) return false; 22 | StrItem strItem = (StrItem) o; 23 | return Objects.equals(strValue, strItem.strValue); 24 | } 25 | 26 | @Override 27 | public int hashCode() { 28 | return Objects.hash(strValue); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/imcode/imitem/VarItem.java: -------------------------------------------------------------------------------- 1 | package imcode.imitem; 2 | 3 | import symbolstruct.entries.AbsVarEntry; 4 | 5 | import java.util.Objects; 6 | 7 | public class VarItem extends IMItem { 8 | public final AbsVarEntry entry; 9 | 10 | protected VarItem(Object entry) { 11 | assert entry instanceof AbsVarEntry; 12 | this.entry = (AbsVarEntry) entry; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return entry.name; 18 | } 19 | 20 | @Override 21 | public boolean equals(Object o) { 22 | if (this == o) return true; 23 | if (o == null || getClass() != o.getClass()) return false; 24 | VarItem varItem = (VarItem) o; 25 | return entry.equals(varItem.entry); 26 | } 27 | 28 | @Override 29 | public int hashCode() { 30 | return Objects.hash(entry); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/improve/component/BasicBlock.java: -------------------------------------------------------------------------------- 1 | package improve.component; 2 | 3 | import imcode.imexp.AssignByVarExp; 4 | import imcode.imexp.IMExp; 5 | import imcode.imitem.VarItem; 6 | import symbolstruct.entries.ConstValueEntry; 7 | import symbolstruct.entries.Entry; 8 | 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.HashSet; 12 | import java.util.Objects; 13 | 14 | /** 15 | * 基本块 16 | */ 17 | public class BasicBlock { 18 | public ArrayList imexps; // 每个基本块包含多条中间代码 19 | public FlowGraph flowGraph; // 每个基本块从属于一个流图 20 | public String name; // 每个基本块分配一个名称,来对其进行唯一标识 21 | 22 | public ArrayList pre; // 前继基本块 23 | 24 | public ArrayList post; // 后继基本块 25 | 26 | //活跃变量 27 | public HashSet activeDef; 28 | public HashSet activeUse; 29 | public HashSet activeIn; 30 | public HashSet activeOut; 31 | 32 | // 到达定义 33 | public HashSet arriveIn; 34 | public HashSet arriveOut; 35 | public HashSet arriveGen; 36 | public HashSet arriveKill; 37 | 38 | // 可用表达式 39 | public HashSet validIn; 40 | public HashSet validOut; 41 | public HashSet validGen; 42 | public HashSet validKill; 43 | 44 | //赋值表达式 45 | public HashSet assignIn; 46 | public HashSet assignOut; 47 | public HashSet assignGen; 48 | public HashSet assignKill; 49 | 50 | protected BasicBlock(ArrayList exps, FlowGraph graph, String name) { 51 | this.imexps = exps; 52 | this.flowGraph = graph; 53 | this.pre = new ArrayList<>(); 54 | this.post = new ArrayList<>(); 55 | 56 | this.activeDef = new HashSet<>(); 57 | this.activeUse = new HashSet<>(); 58 | this.activeIn = new HashSet<>(); 59 | this.activeOut = new HashSet<>(); 60 | 61 | this.arriveIn = new HashSet<>(); 62 | this.arriveOut = new HashSet<>(); 63 | this.arriveGen= new HashSet<>(); 64 | this.arriveKill = new HashSet<>(); 65 | 66 | this.validOut = new HashSet<>(); 67 | this.validIn = new HashSet<>(); 68 | this.validGen = new HashSet<>(); 69 | this.validKill = new HashSet<>(); 70 | 71 | this.assignIn = new HashSet<>(); 72 | this.assignOut = new HashSet<>(); 73 | this.assignGen = new HashSet<>(); 74 | this.assignKill = new HashSet<>(); 75 | 76 | this.name = name; 77 | } 78 | 79 | public ArrayList dump() { 80 | return this.imexps; 81 | } 82 | 83 | public IMExp getLastExp() { 84 | if (this.imexps.size() == 0) { 85 | return null; 86 | } 87 | return this.imexps.get(this.imexps.size() - 1); 88 | } 89 | 90 | @Override 91 | public String toString() { 92 | StringBuilder builder = new StringBuilder(); 93 | builder.append(name + ":\n"); 94 | 95 | builder.append("pre:"); 96 | 97 | for(BasicBlock block:this.pre) { 98 | builder.append(block.name+" "); 99 | } 100 | builder.append("\n"); 101 | 102 | 103 | builder.append("post:"); 104 | 105 | for(BasicBlock block:this.post) { 106 | builder.append(block.name+" "); 107 | } 108 | 109 | builder.append("\n"); 110 | 111 | for (IMExp exp : imexps) { 112 | builder.append(exp + "\n"); 113 | } 114 | 115 | builder.append("active in:["); 116 | for (Entry e : activeIn) { 117 | builder.append(e.name + " "); 118 | } 119 | builder.append("]\n"); 120 | 121 | builder.append("active out:["); 122 | for (Entry e : activeOut) { 123 | builder.append(e.name + " "); 124 | } 125 | builder.append("]\n"); 126 | 127 | builder.append("active def:["); 128 | for (Entry e : activeDef) { 129 | builder.append(e.name + " "); 130 | } 131 | builder.append("]\n"); 132 | 133 | builder.append("active use:["); 134 | for (Entry e : activeUse) { 135 | builder.append(e.name + " "); 136 | } 137 | builder.append("]\n"); 138 | 139 | builder.append("valid in:["); 140 | for (ValidExp e : validIn) { 141 | builder.append(e.exp + " "); 142 | } 143 | builder.append("]\n"); 144 | 145 | builder.append("valid out:["); 146 | for (ValidExp e : validOut) { 147 | builder.append(e.exp + " "); 148 | } 149 | builder.append("]\n"); 150 | 151 | builder.append("valid gen:["); 152 | for (ValidExp e : validGen) { 153 | builder.append(e.exp + " "); 154 | } 155 | builder.append("]\n"); 156 | 157 | builder.append("valid kill:["); 158 | for (ValidExp e : validKill) { 159 | builder.append(e.exp + " "); 160 | } 161 | builder.append("]\n"); 162 | 163 | builder.append("assign in:["); 164 | for (IMExp e : assignIn) { 165 | builder.append(e + " "); 166 | } 167 | builder.append("]\n"); 168 | 169 | builder.append("assign out:["); 170 | for (IMExp e : assignOut) { 171 | builder.append(e + " "); 172 | } 173 | builder.append("]\n"); 174 | 175 | builder.append("assign gen:["); 176 | for (IMExp e : assignGen) { 177 | builder.append(e + " "); 178 | } 179 | builder.append("]\n"); 180 | 181 | builder.append("assign kill:["); 182 | for (IMExp e : assignKill) { 183 | builder.append(e + " "); 184 | } 185 | builder.append("]\n"); 186 | 187 | 188 | return builder.toString(); 189 | } 190 | 191 | @Override 192 | public boolean equals(Object o) { 193 | if (this == o) return true; 194 | if (o == null || getClass() != o.getClass()) return false; 195 | BasicBlock block = (BasicBlock) o; 196 | return this.name.equals((block).name); 197 | } 198 | 199 | @Override 200 | public int hashCode() { 201 | return Objects.hash(name, flowGraph); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/improve/component/ValidExp.java: -------------------------------------------------------------------------------- 1 | package improve.component; 2 | 3 | import global.Error; 4 | import imcode.imexp.*; 5 | import imcode.imitem.VarItem; 6 | import symbolstruct.entries.Entry; 7 | 8 | import java.util.Objects; 9 | 10 | import static java.lang.Math.max; 11 | import static java.lang.Math.min; 12 | 13 | public class ValidExp { 14 | IMExp exp; 15 | 16 | public ValidExp(IMExp exp) { 17 | if (exp instanceof AddExp || 18 | exp instanceof SubExp || 19 | exp instanceof MulExp || 20 | exp instanceof DivExp || 21 | exp instanceof ModExp) { 22 | this.exp = exp; 23 | } else { 24 | Error.warning("Invalid exp put into ValidExp"); 25 | } 26 | } 27 | 28 | @Override 29 | public boolean equals(Object o) { 30 | if (this == o) return true; 31 | if (o == null || getClass() != o.getClass()) return false; 32 | ValidExp validExp = (ValidExp) o; 33 | IMExp otherExp = validExp.exp; 34 | 35 | if (!exp.getClass().equals(validExp.exp.getClass())) { 36 | return false; 37 | } 38 | 39 | if (exp instanceof MulExp || exp instanceof DivExp || exp instanceof ModExp) { 40 | return exp.item2.equals(otherExp.item2) && exp.item3.equals(otherExp.item3); 41 | } else { 42 | return (exp.item2.equals(otherExp.item2) && exp.item3.equals(otherExp.item3)) || 43 | (exp.item3.equals(otherExp.item2) && exp.item2.equals(otherExp.item3)); 44 | } 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | if (exp instanceof MulExp || exp instanceof DivExp || exp instanceof ModExp) { 50 | return Objects.hash(exp.getClass()) + Objects.hash(exp.item2) + Objects.hash(exp.item3); 51 | } else { 52 | // 保证 a+b 和 b+a 是一致的 53 | int hash_a = max(Objects.hash(exp.item2), Objects.hash(exp.item3)); 54 | int hash_b = min(Objects.hash(exp.item2), Objects.hash(exp.item3)); 55 | int ret = Objects.hash(exp.getClass()) + hash_a + hash_b; 56 | return ret; 57 | } 58 | } 59 | 60 | public Boolean in(Entry e) { 61 | VarItem item2 = (VarItem) exp.item2; 62 | VarItem item3 = (VarItem) exp.item3; 63 | return e.equals(item2.entry) || e.equals(item3.entry); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/improve/component/optimizers/ConstOptimizer.java: -------------------------------------------------------------------------------- 1 | package improve.component.optimizers; 2 | 3 | import imcode.imexp.*; 4 | import imcode.imitem.IMItemFac; 5 | import imcode.imitem.IMItemType; 6 | import imcode.imitem.VarItem; 7 | import improve.component.BasicBlock; 8 | import symbolstruct.entries.ConstFeature; 9 | import symbolstruct.entries.ConstValueEntry; 10 | import symbolstruct.entries.ConstVarEntry; 11 | import symbolstruct.entries.Entry; 12 | 13 | import java.util.ArrayList; 14 | import java.util.HashMap; 15 | 16 | public class ConstOptimizer extends Optimizer { 17 | public ConstOptimizer(ArrayList exps, ArrayList blocks, HashMap flowGraph) { 18 | super(exps, blocks, flowGraph); 19 | this.optimize(); 20 | } 21 | 22 | @Override 23 | protected void optimize() { 24 | for (int i = 0; i < this.blocks.size(); i++) { 25 | BasicBlock curBlock = this.blocks.get(i); 26 | 27 | // 正序遍历,进行常量传播 28 | for (int j = 0; j < curBlock.imexps.size(); j++) { 29 | IMExp curExp = curBlock.imexps.get(j); 30 | if (!(curExp.item1 instanceof VarItem)) { 31 | continue; 32 | } 33 | Entry toReplace = ((VarItem) curExp.item1).entry; 34 | Entry canReplaceBy = extractReplaceEntry(curExp); 35 | if (canReplaceBy != null) { 36 | Boolean stopFlag = false; 37 | for (int k = j + 1; k < curBlock.imexps.size(); k++) { 38 | IMExp toExp = curBlock.imexps.get(k); 39 | if (stopFlag) { 40 | break; 41 | } 42 | if (toExp.item1 instanceof VarItem && toReplace.equals(((VarItem) toExp.item1).entry)) { 43 | stopFlag = true; 44 | } 45 | replaceCertainEntry(toExp, toReplace, canReplaceBy); 46 | } 47 | } 48 | } 49 | 50 | // 逆序遍历,删除常量传播后无用的代码 51 | for (int j = curBlock.imexps.size() - 1; j >= 0; j--) { 52 | IMExp curExp = curBlock.imexps.get(j); 53 | 54 | // 仅考虑被赋值变量是变量类型的语句 55 | if (!(curExp.item1 instanceof VarItem)) { 56 | continue; 57 | } 58 | 59 | if (curExp instanceof AssignByGetInt || curExp instanceof AssignToAddrExp) { 60 | continue; 61 | } 62 | 63 | // 如果是被赋值变量是全局变量,那么不能删 64 | if (((VarItem) curExp.item1).entry.isGlobal() && 65 | !((VarItem) curExp.item1).entry.name.contains("_TEMPnym")) { 66 | continue; 67 | } 68 | 69 | // 如果out集合中含有该被赋值变量,那么说明它不能删 70 | if (curBlock.activeOut.contains(((VarItem) curExp.item1).entry)) { 71 | continue; 72 | } 73 | 74 | // 如果有该基本块内含有该赋值变量,那么说明它不能删 75 | Boolean canRemove = true; 76 | for (int k = j + 1; k < curBlock.imexps.size(); k++) { 77 | IMExp toExp = curBlock.imexps.get(k); 78 | if (curExp.item1.equals(toExp.item2) || 79 | curExp.item1.equals(toExp.item3)) { 80 | canRemove = false; 81 | break; 82 | } 83 | } 84 | 85 | // 执行删除 86 | if (canRemove) { 87 | // 删除表达式不要忘记维护好相关数据结构 88 | curBlock.imexps.remove(j); 89 | this.exp2block.remove(curExp); 90 | this.inExps.remove(curExp); 91 | } 92 | } 93 | } 94 | 95 | 96 | for (int i = 0; i < this.blocks.size(); i++) { 97 | this.optExps.addAll(this.blocks.get(i).imexps); 98 | } 99 | } 100 | 101 | 102 | private void replaceCertainEntry(IMExp exp, Entry replaced, Entry by) { 103 | if (exp.item2 != null && exp.item2 instanceof VarItem && ((VarItem) exp.item2).entry.equals(replaced)) { 104 | exp.item2 = IMItemFac.gen(IMItemType.Var, by); 105 | } 106 | if (exp.item3 != null && exp.item3 instanceof VarItem && ((VarItem) exp.item3).entry.equals(replaced)) { 107 | exp.item3 = IMItemFac.gen(IMItemType.Var, by); 108 | } 109 | } 110 | 111 | private Entry extractReplaceEntry(IMExp exp) { 112 | if (exp instanceof AssignByVarExp) { 113 | Entry toCheck = ((VarItem) exp.item2).entry; 114 | if (toCheck instanceof ConstVarEntry || toCheck instanceof ConstValueEntry) { 115 | Entry constEntry = new ConstValueEntry((Integer) ((ConstFeature) toCheck).getValue()); 116 | return constEntry; 117 | } else { 118 | return toCheck; 119 | } 120 | } else if (exp instanceof AddExp) { 121 | Entry opA = ((VarItem) exp.item2).entry; 122 | Entry opB = ((VarItem) exp.item3).entry; 123 | if ((opA instanceof ConstVarEntry || opA instanceof ConstValueEntry) && 124 | (opB instanceof ConstVarEntry || opB instanceof ConstValueEntry)) { 125 | Integer result = ((Integer) ((ConstFeature) opA).getValue()) + ((Integer) ((ConstFeature) opB).getValue()); 126 | Entry constEntry = new ConstValueEntry(result); 127 | return constEntry; 128 | } 129 | } else if (exp instanceof SubExp) { 130 | Entry opA = ((VarItem) exp.item2).entry; 131 | Entry opB = ((VarItem) exp.item3).entry; 132 | if ((opA instanceof ConstVarEntry || opA instanceof ConstValueEntry) && 133 | (opB instanceof ConstVarEntry || opB instanceof ConstValueEntry)) { 134 | Integer result = ((Integer) ((ConstFeature) opA).getValue()) - ((Integer) ((ConstFeature) opB).getValue()); 135 | Entry constEntry = new ConstValueEntry(result); 136 | return constEntry; 137 | } 138 | } else if (exp instanceof MulExp) { 139 | Entry opA = ((VarItem) exp.item2).entry; 140 | Entry opB = ((VarItem) exp.item3).entry; 141 | if ((opA instanceof ConstVarEntry || opA instanceof ConstValueEntry) && 142 | (opB instanceof ConstVarEntry || opB instanceof ConstValueEntry)) { 143 | Integer result = ((Integer) ((ConstFeature) opA).getValue()) * ((Integer) ((ConstFeature) opB).getValue()); 144 | Entry constEntry = new ConstValueEntry(result); 145 | return constEntry; 146 | } 147 | } else if (exp instanceof DivExp) { 148 | Entry opA = ((VarItem) exp.item2).entry; 149 | Entry opB = ((VarItem) exp.item3).entry; 150 | if ((opA instanceof ConstVarEntry || opA instanceof ConstValueEntry) && 151 | (opB instanceof ConstVarEntry || opB instanceof ConstValueEntry)) { 152 | Integer result = ((Integer) ((ConstFeature) opA).getValue()) / ((Integer) ((ConstFeature) opB).getValue()); 153 | Entry constEntry = new ConstValueEntry(result); 154 | return constEntry; 155 | } 156 | } else if (exp instanceof ModExp) { 157 | Entry opA = ((VarItem) exp.item2).entry; 158 | Entry opB = ((VarItem) exp.item3).entry; 159 | if ((opA instanceof ConstVarEntry || opA instanceof ConstValueEntry) && 160 | (opB instanceof ConstVarEntry || opB instanceof ConstValueEntry)) { 161 | Integer result = ((Integer) ((ConstFeature) opA).getValue()) % ((Integer) ((ConstFeature) opB).getValue()); 162 | Entry constEntry = new ConstValueEntry(result); 163 | return constEntry; 164 | } 165 | } else if (exp instanceof BeqExp) { 166 | 167 | } 168 | return null; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/improve/component/optimizers/GlobalExpOptimizer.java: -------------------------------------------------------------------------------- 1 | package improve.component.optimizers; 2 | 3 | import component.datatype.IntType; 4 | import global.Config; 5 | import imcode.imexp.*; 6 | import imcode.imitem.IMItemFac; 7 | import imcode.imitem.IMItemType; 8 | import imcode.imitem.VarItem; 9 | import improve.component.BasicBlock; 10 | import improve.component.ValidExp; 11 | import symbolstruct.Region; 12 | import symbolstruct.entries.Entry; 13 | import symbolstruct.entries.VarEntry; 14 | 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.HashSet; 18 | 19 | public class GlobalExpOptimizer extends Optimizer { 20 | Region belongRegion; 21 | 22 | public GlobalExpOptimizer(ArrayList exps, ArrayList blocks, 23 | HashMap exp2block, Region region) { 24 | super(exps, blocks, exp2block); 25 | this.belongRegion = region; 26 | optimize(); 27 | } 28 | 29 | @Override 30 | protected void optimize() { 31 | HashSet validExps = new HashSet<>(); 32 | for (IMExp exp : this.inExps) { 33 | if (exp instanceof AddExp || 34 | exp instanceof SubExp || 35 | exp instanceof MulExp || 36 | exp instanceof DivExp || 37 | exp instanceof ModExp) { 38 | validExps.add(new ValidExp(exp)); 39 | } 40 | } 41 | 42 | for (IMExp exp : this.inExps) { 43 | if (!(exp instanceof AddExp || 44 | exp instanceof SubExp || 45 | exp instanceof MulExp || 46 | exp instanceof DivExp || 47 | exp instanceof ModExp)) { 48 | continue; // 跳过不涉及计算的语句 49 | } 50 | 51 | ValidExp validExp = new ValidExp(exp); 52 | BasicBlock inBlock = exp2block.get(exp); 53 | 54 | if (!inBlock.validIn.contains(validExp)) { 55 | continue; 56 | } 57 | 58 | Boolean valid = true; 59 | for (IMExp otherExp : inBlock.imexps) { 60 | if (otherExp.equals(exp)) { 61 | break; 62 | } 63 | 64 | if (!(otherExp.item1 instanceof VarItem)) { 65 | continue; 66 | } 67 | 68 | Entry assigned = ((VarItem) otherExp.item1).entry; 69 | if (validExp.in(assigned)) { 70 | valid = false; 71 | break; 72 | } 73 | } 74 | 75 | if (!valid) { 76 | break; 77 | } 78 | 79 | Entry newEntry = new VarEntry("GLB_EXP_OPT_" + Config.getTmpNameSed(), new IntType()); 80 | newEntry.in = this.belongRegion.scope; 81 | this.belongRegion.frame.insertEntry(newEntry); 82 | 83 | HashMap isBlockDone = new HashMap<>(); 84 | for (BasicBlock preBlk : inBlock.pre) { 85 | travelAndReplace(exp, isBlockDone, validExp, preBlk, newEntry); 86 | } 87 | 88 | Entry toAssign = ((VarItem) exp.item1).entry; 89 | for (int i = 0; i < inBlock.imexps.size(); i++) { 90 | if (inBlock.imexps.get(i).equals(exp)) { 91 | inBlock.imexps.set(i, IMFac.gen(IMExpType.AssignByVar, toAssign, newEntry)); 92 | } 93 | } 94 | } 95 | 96 | for (BasicBlock blk : this.blocks) { 97 | this.optExps.addAll(blk.imexps); 98 | } 99 | } 100 | 101 | private void travelAndReplace(IMExp fromExp, HashMap isBlockDone, 102 | ValidExp toReplace, BasicBlock blk, Entry entry) { 103 | if (isBlockDone.getOrDefault(blk, false) == true) { 104 | return; 105 | } 106 | 107 | isBlockDone.put(blk, true); 108 | 109 | for (int i = blk.imexps.size() - 1; i >= 0; i--) { 110 | IMExp exp = blk.imexps.get(i); 111 | 112 | if(exp.equals(fromExp)) { 113 | continue; 114 | } 115 | 116 | if (!(exp instanceof AddExp || 117 | exp instanceof SubExp || 118 | exp instanceof MulExp || 119 | exp instanceof DivExp || 120 | exp instanceof ModExp)) { 121 | continue; // 跳过不涉及计算的语句 122 | } 123 | ValidExp validExp = new ValidExp(exp); 124 | if (validExp.equals(toReplace)) { 125 | Entry oldAssigned = ((VarItem) exp.item1).entry; 126 | exp.item1 = IMItemFac.gen(IMItemType.Var, entry); 127 | IMExp newExp = IMFac.gen(IMExpType.AssignByVar, oldAssigned, entry); 128 | // 新增表达式不要忘记维护好相关的数据结构 129 | blk.imexps.add(i + 1, newExp); 130 | this.exp2block.put(newExp, blk); 131 | return; 132 | } 133 | } 134 | 135 | for (BasicBlock preBlk : blk.pre) { 136 | travelAndReplace(fromExp, isBlockDone, toReplace, preBlk, entry); 137 | } 138 | } 139 | } 140 | 141 | -------------------------------------------------------------------------------- /src/improve/component/optimizers/Optimizer.java: -------------------------------------------------------------------------------- 1 | package improve.component.optimizers; 2 | 3 | import imcode.imexp.IMExp; 4 | import improve.component.BasicBlock; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | 9 | public abstract class Optimizer { 10 | protected ArrayList inExps; 11 | protected ArrayList optExps; 12 | protected ArrayList blocks; 13 | public HashMap exp2block; 14 | 15 | protected Optimizer(ArrayList exps, ArrayList blocks, HashMap exp2block) { 16 | this.exp2block = exp2block; 17 | this.blocks = blocks; 18 | this.inExps = exps; 19 | this.optExps = new ArrayList<>(); 20 | } 21 | 22 | protected abstract void optimize(); 23 | 24 | public ArrayList dump() { 25 | return this.optExps; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/improve/component/optimizers/SeekOptimizer.java: -------------------------------------------------------------------------------- 1 | package improve.component.optimizers; 2 | 3 | import imcode.imexp.AssignByVarExp; 4 | import imcode.imexp.IMExp; 5 | import imcode.imitem.IMItemFac; 6 | import imcode.imitem.IMItemType; 7 | import imcode.imitem.VarItem; 8 | import improve.component.BasicBlock; 9 | import symbolstruct.entries.Entry; 10 | 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.HashSet; 14 | 15 | public class SeekOptimizer extends Optimizer { 16 | 17 | private HashMap> expArriveIn; 18 | 19 | public SeekOptimizer(ArrayList exps, ArrayList blocks, 20 | HashMap map, 21 | HashMap> expArriveIn) { 22 | super(exps, blocks, map); 23 | this.expArriveIn = expArriveIn; 24 | optimize(); 25 | } 26 | 27 | @Override 28 | protected void optimize() { 29 | for (BasicBlock blk : this.blocks) { 30 | for (int i = 0; i < blk.imexps.size(); i++) { 31 | IMExp exp = blk.imexps.get(i); 32 | if (!(exp instanceof AssignByVarExp)) { 33 | continue; 34 | } 35 | 36 | // exp: x:=y 37 | Entry x = ((VarItem) exp.item1).entry; 38 | Entry y = ((VarItem) exp.item2).entry; 39 | 40 | ArrayList references = new ArrayList<>(); 41 | 42 | // 试图寻找所有其引用 43 | for (IMExp otherExp : this.inExps) { 44 | 45 | // 跳过没有引用该变量x的语句 46 | if (!((otherExp.item2 instanceof VarItem && ((VarItem) otherExp.item2).entry.equals(x)) || 47 | (otherExp.item3 instanceof VarItem && ((VarItem) otherExp.item3).entry.equals(x)))) { 48 | continue; 49 | } 50 | 51 | if (!expArriveIn.getOrDefault(otherExp, new HashSet<>()).contains(exp)) { 52 | continue; 53 | } 54 | 55 | references.add(otherExp); 56 | } 57 | 58 | // 检查所有引用是否符合要求 59 | Boolean removable = true; 60 | for (int k = 0; k < references.size(); k++) { 61 | IMExp reference = references.get(k); 62 | BasicBlock refBlock = exp2block.get(reference); 63 | 64 | // 如果赋值语句exp和引用语句otherExp处在同一个基本块 65 | if (refBlock.equals(blk)) { 66 | Boolean valid = true; 67 | Integer assignIndex = null; 68 | Integer referenceIndex = null; 69 | for (int g = 0; g < refBlock.imexps.size(); g++) { 70 | IMExp potentialAssignExp = refBlock.imexps.get(g); 71 | if (potentialAssignExp.equals(exp)) assignIndex = g; 72 | if (potentialAssignExp.equals(reference)) referenceIndex = g; 73 | } 74 | 75 | // 如果赋值语句在引用之前,那么需要保证两者之间不存在新的对x和y的赋值 76 | if (assignIndex < referenceIndex) { 77 | for (int g = assignIndex + 1; g < referenceIndex; g++) { 78 | IMExp potentialAssignExp = refBlock.imexps.get(g); 79 | // 跳过非赋值语句 80 | if (!(potentialAssignExp.item1 instanceof VarItem)) { 81 | continue; 82 | } 83 | Entry assigned = ((VarItem) potentialAssignExp.item1).entry; 84 | if ((assigned.equals(x) || assigned.equals(y))) { 85 | valid = false; 86 | break; 87 | } 88 | } 89 | 90 | if(!valid) { 91 | removable = false; 92 | break; 93 | } else { 94 | continue; 95 | } 96 | } else { 97 | // 如果引用语句在赋值语句之前(这是可能的,考虑基本块的循环),则只考虑从基本块开始计算的路径 98 | // 则说明需要赋值语句处于该循环块的入口才行,类似其他非同一基本块的情况 99 | // 啥也不敢,以跳出IF; 100 | } 101 | } 102 | 103 | if (!refBlock.assignIn.contains(exp)) { 104 | removable = false; 105 | break; 106 | } 107 | 108 | Boolean valid = true; 109 | for (int g = 0; g < refBlock.imexps.size(); g++) { 110 | IMExp potentialAssignExp = refBlock.imexps.get(g); 111 | 112 | //当检查到当前引用语句reference时退出 113 | if (potentialAssignExp.equals(reference)) { 114 | break; 115 | } 116 | 117 | // 跳过非赋值类语句 118 | if (!(potentialAssignExp.item1 instanceof VarItem)) { 119 | continue; 120 | } 121 | 122 | // 如果在reference之前有语句对x或y做出赋值 123 | Entry assigned = ((VarItem) potentialAssignExp.item1).entry; 124 | if (assigned.equals(x) || assigned.equals(y)) { 125 | valid = false; 126 | break; 127 | } 128 | } 129 | 130 | if (!valid) { 131 | removable = false; 132 | break; 133 | } 134 | } 135 | 136 | if (removable && !((VarItem) exp.item1).entry.isGlobal() && 137 | !((VarItem) exp.item1).entry.name.contains("_TEMPnym")) { 138 | // #TRADEOFF 我们仅删除对非临时变量且非全局变量的赋值语句, 139 | // 前者是因为我们的到达定义分析仅针对了非临时变量, 140 | // 后者是因为我们不确定其他函数是否引用全白变量 141 | // 删除表达式不要忘了维护好相关数据结构 142 | blk.imexps.remove(i); 143 | i--; 144 | this.exp2block.remove(exp); 145 | this.inExps.remove(exp); 146 | 147 | for (IMExp reference : references) { 148 | VarItem replace = (VarItem) IMItemFac.gen(IMItemType.Var, y); 149 | 150 | if (reference.item2 instanceof VarItem && ((VarItem) reference.item2).entry.equals(x)) { 151 | reference.item2 = replace; 152 | } 153 | 154 | if (reference.item3 instanceof VarItem && ((VarItem) reference.item3).entry.equals(x)) { 155 | reference.item3 = replace; 156 | } 157 | } 158 | } 159 | } 160 | } 161 | 162 | for (BasicBlock blk : this.blocks) { 163 | this.optExps.addAll(blk.imexps); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/improve/component/regpool/GlbRegPool.java: -------------------------------------------------------------------------------- 1 | package improve.component.regpool; 2 | 3 | import mips.register.Register; 4 | import symbolstruct.CodeText; 5 | import symbolstruct.Region; 6 | import symbolstruct.entries.Entry; 7 | 8 | import java.util.HashMap; 9 | import java.util.HashSet; 10 | 11 | public class GlbRegPool { 12 | private HashMap entry2reg; 13 | private HashMap isLoaded; 14 | private Region region; 15 | 16 | GlbRegPool(HashMap input, Region region) { 17 | this.region = region; 18 | this.entry2reg = input; 19 | this.isLoaded = new HashMap<>(); 20 | } 21 | 22 | Register find(Entry entry) { 23 | return this.entry2reg.get(entry); 24 | } 25 | 26 | Register findNoLoad(Entry entry) { 27 | return this.entry2reg.get(entry); 28 | } 29 | 30 | public void save() { 31 | for (Entry entry : this.entry2reg.keySet()) { 32 | if (entry.isGlobal()) { 33 | CodeText.textNLine(String.format("# Global Register Pool save %s To memory", entry.name)); 34 | CodeText.textNLine(String.format("sw %s %s", this.entry2reg.get(entry), entry.name)); 35 | } // 保存时只保留全局变量 36 | } 37 | } 38 | 39 | public void saveActive(HashSet actives) { 40 | for (Entry entry : this.entry2reg.keySet()) { 41 | if (!actives.contains(entry)) { 42 | continue; // 跳过不活跃的变量 43 | } 44 | if (entry.isGlobal()) { 45 | CodeText.textNLine(String.format("# Global Register Pool save %s To memory", entry.name)); 46 | CodeText.textNLine(String.format("sw %s %s", this.entry2reg.get(entry), entry.name)); 47 | } else { 48 | CodeText.textNLine(String.format("# Global Register Pool save %s To memory", entry.name)); 49 | CodeText.textNLine(String.format("sw %s %d($sp)", this.entry2reg.get(entry), region.frame.offsetMap.get(entry))); 50 | } 51 | } 52 | } 53 | 54 | public void saveGlb() { 55 | for (Entry entry : this.entry2reg.keySet()) { 56 | if (!entry.isGlobal()) { 57 | continue; // 跳过非全局的变量 58 | } 59 | if (entry.isGlobal()) { 60 | CodeText.textNLine(String.format("# Global Register Pool save %s To memory", entry.name)); 61 | CodeText.textNLine(String.format("sw %s %s", this.entry2reg.get(entry), entry.name)); 62 | } else { 63 | CodeText.textNLine(String.format("# Global Register Pool save %s To memory", entry.name)); 64 | CodeText.textNLine(String.format("sw %s %d($sp)", this.entry2reg.get(entry), region.frame.offsetMap.get(entry))); 65 | } 66 | } 67 | } 68 | 69 | public void init() { 70 | CodeText.textNLine("\n# Global Register init"); 71 | for (Entry entry : entry2reg.keySet()) { 72 | if (entry.isGlobal()) { 73 | CodeText.textNLine(String.format("# Global Register Pool load %s From memory", entry.name)); 74 | CodeText.textNLine(String.format("lw %s %s", this.entry2reg.get(entry), entry.name)); 75 | } else if (entry.isParam) { 76 | CodeText.textNLine(String.format("# Global Register Pool load %s From memory", entry.name)); 77 | CodeText.textNLine(String.format("lw %s %d($sp)", this.entry2reg.get(entry), region.frame.offsetMap.get(entry))); 78 | } 79 | // 初始化时不加载非全局也非函数参数的变量 80 | } 81 | } 82 | 83 | public void loadActive(HashSet actives) { 84 | for (Entry entry : entry2reg.keySet()) { 85 | if(!actives.contains(entry)) { 86 | continue; 87 | } 88 | if (entry.isGlobal()) { 89 | CodeText.textNLine(String.format("# Global Register Pool load %s From memory", entry.name)); 90 | CodeText.textNLine(String.format("lw %s %s", this.entry2reg.get(entry), entry.name)); 91 | } else { 92 | CodeText.textNLine(String.format("# Global Register Pool load %s From memory", entry.name)); 93 | CodeText.textNLine(String.format("lw %s %d($sp)", this.entry2reg.get(entry), region.frame.offsetMap.get(entry))); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/improve/component/regpool/LocRegPool.java: -------------------------------------------------------------------------------- 1 | package improve.component.regpool; 2 | 3 | import global.Config; 4 | import imcode.imexp.PrintVarExp; 5 | import improve.component.BasicBlock; 6 | import mips.register.Register; 7 | import symbolstruct.CodeText; 8 | import symbolstruct.FuncRegion; 9 | import symbolstruct.Region; 10 | import symbolstruct.entries.Entry; 11 | 12 | import java.util.HashMap; 13 | import java.util.LinkedList; 14 | 15 | public class LocRegPool { 16 | private HashMap entry2reg; 17 | private HashMap isFree; 18 | private LinkedList queue; 19 | private Region region; 20 | 21 | LocRegPool(Region region) { 22 | this.region = region; 23 | this.entry2reg = new HashMap<>(); 24 | this.isFree = new HashMap<>(); 25 | for (Register register : Config.getLocReg()) { 26 | isFree.put(register, true); 27 | } 28 | this.queue = new LinkedList<>(); 29 | } 30 | 31 | Register find(Entry entry) { 32 | if (this.entry2reg.get(entry) == null) { 33 | return this.put(entry); 34 | } 35 | return this.entry2reg.get(entry); 36 | } 37 | 38 | Register findNoLoad(Entry entry) { 39 | if (this.entry2reg.get(entry) == null) { 40 | return this.putNoLoad(entry); 41 | } 42 | return this.entry2reg.get(entry); 43 | } 44 | 45 | public void save(BasicBlock inBlock) { 46 | for (Entry entry : this.entry2reg.keySet()) { 47 | // 如果这个entry在后继基本块不会被访问,而且不是全局变量,那么我们不将其存入内存 48 | if ((!inBlock.activeOut.contains(entry)) && (!entry.isGlobal())) continue; 49 | CodeText.textNLine(String.format("# Local Register Pool save %s To memory", entry.name)); 50 | if (entry.isGlobal()) { 51 | CodeText.textNLine(String.format("sw %s %s", this.entry2reg.get(entry), entry.name)); 52 | } else { 53 | CodeText.textNLine(String.format("sw %s %d($sp)", this.entry2reg.get(entry), region.frame.offsetMap.get(entry))); 54 | } 55 | } 56 | } 57 | 58 | public void init(BasicBlock inBlock) { 59 | this.entry2reg = new HashMap<>(); 60 | this.isFree = new HashMap<>(); 61 | for (Register register : Config.getLocReg()) { 62 | isFree.put(register, true); 63 | } 64 | this.queue = new LinkedList<>(); 65 | } 66 | 67 | private Register putNoLoad(Entry entry) { 68 | for (Register register : Config.getLocReg()) { 69 | if (isFree.get(register)) { 70 | this.entry2reg.put(entry, register); 71 | this.isFree.put(register, false); 72 | this.queue.add(entry); 73 | return register; 74 | } 75 | } 76 | 77 | Entry toRemove = this.queue.poll(); 78 | Register toFree = this.entry2reg.get(toRemove); 79 | this.entry2reg.remove(toRemove); 80 | 81 | CodeText.textNLine(String.format("# Local Register Pool save %s To memory", toRemove.name)); 82 | if (toRemove.isGlobal()) { 83 | CodeText.textNLine(String.format("sw %s %s", toFree, toRemove.name)); 84 | } else { 85 | CodeText.textNLine(String.format("sw %s %d($sp)", toFree, region.frame.offsetMap.get(toRemove))); 86 | } 87 | 88 | this.entry2reg.put(entry, toFree); 89 | this.queue.add(entry); 90 | return toFree; 91 | } 92 | 93 | private Register put(Entry entry) { 94 | for (Register register : Config.getLocReg()) { 95 | if (isFree.get(register)) { 96 | CodeText.textNLine(String.format("# Local Register Pool load %s From memory", entry.name)); 97 | if (entry.isGlobal()) { 98 | CodeText.textNLine(String.format("lw %s %s", register, entry.name)); 99 | } else { 100 | CodeText.textNLine(String.format("lw %s %d($sp)", register, region.frame.offsetMap.get(entry))); 101 | } 102 | this.entry2reg.put(entry, register); 103 | this.isFree.put(register, false); 104 | this.queue.add(entry); 105 | return register; 106 | } 107 | } 108 | 109 | Entry toRemove = this.queue.poll(); 110 | Register toFree = this.entry2reg.get(toRemove); 111 | this.entry2reg.remove(toRemove); 112 | 113 | CodeText.textNLine(String.format("# Local Register Pool save %s To memory", toRemove.name)); 114 | if (toRemove.isGlobal()) { 115 | CodeText.textNLine(String.format("sw %s %s", toFree, toRemove.name)); 116 | } else { 117 | CodeText.textNLine(String.format("sw %s %d($sp)", toFree, region.frame.offsetMap.get(toRemove))); 118 | } 119 | 120 | this.entry2reg.put(entry, toFree); 121 | this.queue.add(entry); 122 | 123 | if (entry.isGlobal()) { 124 | CodeText.textNLine(String.format("lw %s %s", toFree, entry.name)); 125 | } else { 126 | CodeText.textNLine(String.format("lw %s %d($sp)", toFree, region.frame.offsetMap.get(entry))); 127 | } 128 | return toFree; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/improve/component/regpool/RegPool.java: -------------------------------------------------------------------------------- 1 | package improve.component.regpool; 2 | 3 | import mips.register.Register; 4 | import symbolstruct.CodeText; 5 | import symbolstruct.Frame; 6 | import symbolstruct.FuncRegion; 7 | import symbolstruct.Region; 8 | import symbolstruct.entries.ConstValueEntry; 9 | import symbolstruct.entries.Entry; 10 | 11 | import java.util.HashMap; 12 | 13 | public class RegPool { 14 | public LocRegPool locPool; 15 | public GlbRegPool glbPool; 16 | private FuncRegion region; 17 | 18 | public RegPool(Region region, HashMap colorMap) { 19 | this.glbPool = new GlbRegPool(colorMap, region); 20 | this.locPool = new LocRegPool(region); 21 | if (region instanceof FuncRegion) { 22 | this.region = (FuncRegion) region; 23 | } 24 | } 25 | 26 | public String find(Entry entry) { 27 | Register ret = this.glbPool.find(entry); 28 | if (ret == null) { 29 | ret = this.locPool.find(entry); 30 | } 31 | return ret.toString(); 32 | } 33 | 34 | public String findNoLoad(Entry entry) { 35 | Register ret = this.glbPool.findNoLoad(entry); 36 | if (ret == null) { 37 | ret = this.locPool.findNoLoad(entry); 38 | } 39 | return ret.toString(); 40 | } 41 | 42 | public String allocTmpReg() { 43 | return "$fp"; 44 | } 45 | 46 | public void freeTmpReg(String register) { 47 | ; 48 | } 49 | 50 | public Frame getFrame() { 51 | return this.region.frame; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/mips/exps/MIPSExp.java: -------------------------------------------------------------------------------- 1 | package mips.exps; 2 | 3 | public abstract class MIPSExp { 4 | } 5 | -------------------------------------------------------------------------------- /src/mips/exps/MIType.java: -------------------------------------------------------------------------------- 1 | package mips.exps; 2 | 3 | import mips.register.Register; 4 | 5 | public abstract class MIType extends MIPSExp{ 6 | private Register rs; 7 | private Register rt; 8 | 9 | private Integer immediate; 10 | 11 | public abstract String toString(); 12 | } 13 | -------------------------------------------------------------------------------- /src/mips/exps/MRType.java: -------------------------------------------------------------------------------- 1 | package mips.exps; 2 | 3 | import mips.register.Register; 4 | 5 | /** 6 | * MIPS R型指令 7 | * 接收三个寄存器变量,一个立即数变量(用于移位指令) 8 | */ 9 | public abstract class MRType extends MIPSExp{ 10 | private Register rs; 11 | private Register rt; 12 | private Register rd; 13 | 14 | private Integer shamt; 15 | 16 | public abstract String toString(); 17 | } 18 | -------------------------------------------------------------------------------- /src/mips/register/Register.java: -------------------------------------------------------------------------------- 1 | package mips.register; 2 | 3 | public enum Register { 4 | $zero, 5 | $at, 6 | $v0, $v1, 7 | $a0, $a1, $a2, $a3, 8 | $t0, $t1, $t2, $t3, $t4, $t5, $t6, $t7, 9 | $s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7, 10 | $t8, $t9, 11 | $k0, $k1, 12 | $gp, 13 | $sp, 14 | $fp, 15 | $ra 16 | } 17 | -------------------------------------------------------------------------------- /src/symbolstruct/CodeRegion.java: -------------------------------------------------------------------------------- 1 | package symbolstruct; 2 | 3 | import global.Logger; 4 | import imcode.imexp.IMExp; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | 9 | /** 10 | * 整个程序的目标代码生成模块 11 | */ 12 | public class CodeRegion { 13 | public ArrayList regions; // 多个函数模块 14 | public GlobalRegion glbRegion; // 全局模块 15 | 16 | public HashMap strMap; // 字符表 17 | public Region curRegion; 18 | 19 | public CodeRegion() { 20 | this.regions = new ArrayList<>(); 21 | this.strMap = new HashMap<>(); 22 | } 23 | 24 | public void addRegion(FuncRegion region) { 25 | this.regions.add(region); 26 | this.curRegion = region; 27 | } 28 | 29 | public void addGlbRegion(GlobalRegion region) { 30 | this.glbRegion = region; 31 | this.curRegion = region; 32 | } 33 | 34 | public void addStr(String name, String value) { 35 | this.strMap.put(name, value); 36 | } 37 | 38 | public void gen() { 39 | glbRegion.gen(); // 在data区内声明全局变量并在text区进行初始化,一定要在字符表声明前进行,因为全局变量必须字对齐。如果先声明字符表会破坏这一约束。 40 | 41 | for (String e : strMap.keySet()) { 42 | CodeText.dataNLine(String.format("%s: .ascii \"%s\\0\"", e, strMap.get(e))); 43 | } 44 | // 在data区内声明字符表 45 | 46 | CodeText.textNLine("jal main"); 47 | CodeText.textNLine("nop"); 48 | CodeText.textNLine("li $v0, 10"); 49 | CodeText.textNLine("syscall"); 50 | // 跳转到main函数入口,并且在程序结束后正常退出 51 | 52 | for (FuncRegion region : regions) { 53 | region.gen(); 54 | } 55 | // 初始化所有函数模块,详见FuncRegion 56 | 57 | Logger.GetLogger().MIPSLog(".data"); 58 | Logger.GetLogger().MIPSLog(CodeText.dumpData()); 59 | Logger.GetLogger().MIPSLog(".text"); 60 | Logger.GetLogger().MIPSLog(CodeText.dumpText()); 61 | // 将data和text区打印出来 62 | } 63 | 64 | public void addIMExp(IMExp e) { 65 | this.curRegion.imexps.add(e); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/symbolstruct/CodeText.java: -------------------------------------------------------------------------------- 1 | package symbolstruct; 2 | 3 | import component.LineContainer; 4 | 5 | public class CodeText { 6 | private LineContainer dataText; 7 | private LineContainer textText; 8 | private static CodeText instance; 9 | 10 | private CodeText(){ 11 | this.dataText = new LineContainer(); 12 | this.textText = new LineContainer(); 13 | } 14 | 15 | private static CodeText getInstance(){ 16 | if(instance == null){ 17 | instance = new CodeText(); 18 | } 19 | return instance; 20 | } 21 | 22 | /** 23 | * 向.text区写入一行 24 | * @param in 25 | */ 26 | public static void textNLine(String in) { 27 | CodeText.getInstance().textText.addLine(in); 28 | } 29 | 30 | /** 31 | * 向.data区写入一行 32 | * @param in 33 | */ 34 | public static void dataNLine(String in) { 35 | CodeText.getInstance().dataText.addLine(in); 36 | } 37 | 38 | public static String dumpText() { 39 | return CodeText.getInstance().textText.dump(); 40 | } 41 | 42 | public static String dumpData() { 43 | return CodeText.getInstance().dataText.dump(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/symbolstruct/Frame.java: -------------------------------------------------------------------------------- 1 | package symbolstruct; 2 | 3 | import symbolstruct.entries.AbsVarEntry; 4 | import symbolstruct.entries.Entry; 5 | import symbolstruct.entries.FuncEntry; 6 | 7 | import java.lang.reflect.Array; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | 11 | 12 | /** 13 | * Frame 函数栈帧对象 14 | * 其存储了当前函数下所有局部变量和函数参数 15 | * 不同作用域的同名变量通过其所在的Scope来进行区分(这由Entry的hashcode方法支持) 16 | * 注意函数形参的地址 高于 $ra地址 高于 局部变量地址 17 | */ 18 | public class Frame { 19 | public ArrayList allEntries; // 栈帧需要存储的所有符号项 20 | public HashMap offsetMap; // 符号项对象到偏移量的映射 21 | public Integer size; // 栈帧大小,单位为字节 22 | public Integer offsetRA; // $ra所需要存储的位置的偏移地址 23 | 24 | public ArrayList localEntries; 25 | public ArrayList params; 26 | 27 | public Frame(ArrayList params, ArrayList localEntries) { 28 | this.localEntries = localEntries; 29 | this.params = params; 30 | 31 | this.allEntries = new ArrayList<>(); 32 | this.allEntries.addAll(params); 33 | this.allEntries.addAll(localEntries); 34 | 35 | this.offsetMap = new HashMap<>(); 36 | 37 | int offset = 0; //注意参数的排布方式 38 | 39 | for (Entry local : localEntries) { 40 | if (local instanceof AbsVarEntry) { 41 | this.offsetMap.put(local, offset); 42 | offset += ((AbsVarEntry) local).size * 4; 43 | } 44 | } 45 | // 注意我们先将offset建立映射,再将offset+=4 46 | // 这保证我们的参数这栈帧中的偏移从0一直到(frame.size-4) 47 | // 这一处与IMExp.PushParaExp联动,后者保证了将函数参数压入栈时,是从-4开始压入的 48 | 49 | offsetRA = offset; // 将$ra的对应存储地址放在局部变量和参数之间 50 | offset += 4; 51 | 52 | for (int iter = params.size() - 1; iter >= 0; iter--) { 53 | Entry param = params.get(iter); 54 | if (param instanceof AbsVarEntry) { 55 | this.offsetMap.put(param, offset); 56 | offset += ((AbsVarEntry) param).size * 4; 57 | } 58 | } 59 | // 注意参数的顺序是反向,这和我们PushPara时的顺序有关。Push时是从左往右, 60 | // 而我们offset实际上是从低地址到高地址,因此是从右往左依次提高offset的值 61 | 62 | this.size = offset; 63 | 64 | /* 栈帧中存储的大致描述: 65 | * param 1 66 | * param 2 67 | * ______________ 68 | * ra 69 | * -------------- 70 | * local var 1 71 | * local var 2 <=== sp 72 | * */ 73 | } 74 | 75 | public void insertEntry(Entry e) { 76 | // 将新添加的变量加入局部变量中,然后重新构建映射关系 77 | this.localEntries.add(e); 78 | 79 | this.allEntries = new ArrayList<>(); 80 | this.allEntries.addAll(params); 81 | this.allEntries.addAll(localEntries); 82 | 83 | this.offsetMap = new HashMap<>(); 84 | 85 | int offset = 0; 86 | 87 | for (Entry local : localEntries) { 88 | if (local instanceof AbsVarEntry) { 89 | this.offsetMap.put(local, offset); 90 | offset += ((AbsVarEntry) local).size * 4; 91 | } 92 | } 93 | 94 | this.offsetRA = offset; 95 | offset += 4; 96 | 97 | for (int iter = params.size() - 1; iter >= 0; iter--) { 98 | Entry param = params.get(iter); 99 | if (param instanceof AbsVarEntry) { 100 | this.offsetMap.put(param, offset); 101 | offset += ((AbsVarEntry) param).size * 4; 102 | } 103 | } 104 | 105 | this.size = offset; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/symbolstruct/FuncRegion.java: -------------------------------------------------------------------------------- 1 | package symbolstruct; 2 | 3 | import imcode.imexp.IMExp; 4 | import improve.component.FlowGraph; 5 | import symbolstruct.entries.Entry; 6 | 7 | import java.util.ArrayList; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * 负责目标代码中各个函数的转化 12 | */ 13 | public class FuncRegion extends Region{ 14 | 15 | public FuncRegion(String name, Scope scope) { 16 | super(name, scope); 17 | this.imexps = new ArrayList<>(); 18 | } 19 | 20 | public void gen() { 21 | ArrayList param = scope.getParams(); 22 | // 获取当前函数根Scope所声明的形式参数对应的符号项们,这是由Scope::insertParaVar/Array 以及 Converter::FuncFParam支持的机制 23 | 24 | ArrayList local = (ArrayList) scope.dumpAllEntries().stream() 25 | .filter(e -> !param.contains(e)) 26 | .collect(Collectors.toList()); 27 | // 从当前函数根Scope及其子Scope中导出所有声明的符号项,并且过滤掉函数形参 28 | 29 | this.frame = new Frame(param, local); 30 | // 通过形参和局部变量构建其栈帧对象, 详见Frame 31 | 32 | FlowGraph flowGraph = new FlowGraph(this); 33 | // 将当前函数构造成流图,其同时会将流图中的东西导出到CodeText中 34 | } 35 | 36 | @Override 37 | public ArrayList getEntries() { 38 | return this.scope.dumpAllEntries(); 39 | } 40 | 41 | @Override 42 | public void insertEntry(Entry newEntry) { 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/symbolstruct/GlobalRegion.java: -------------------------------------------------------------------------------- 1 | package symbolstruct; 2 | 3 | import imcode.imexp.IMExp; 4 | import improve.component.FlowGraph; 5 | import symbolstruct.entries.AbsVarEntry; 6 | import symbolstruct.entries.Entry; 7 | 8 | import java.util.ArrayList; 9 | import java.util.stream.Collectors; 10 | 11 | public class GlobalRegion extends Region{ 12 | 13 | public GlobalRegion(Scope scope) { 14 | super("#GLOBAL_REGION#", scope); 15 | } 16 | 17 | @Override 18 | public void gen() { 19 | FlowGraph flowGraph = new FlowGraph(this); 20 | } 21 | 22 | @Override 23 | public ArrayList getEntries() { 24 | return (ArrayList) scope.getNowEntries().stream().filter(e -> e.isGlobal()) 25 | .filter(e -> e instanceof AbsVarEntry).collect(Collectors.toList()); 26 | } 27 | 28 | @Override 29 | public void insertEntry(Entry newEntry) { 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/symbolstruct/Region.java: -------------------------------------------------------------------------------- 1 | package symbolstruct; 2 | 3 | import imcode.imexp.IMExp; 4 | import symbolstruct.entries.Entry; 5 | 6 | import java.util.ArrayList; 7 | 8 | public abstract class Region { 9 | public ArrayList imexps; 10 | public Scope scope; 11 | public final String name; 12 | public Frame frame; 13 | 14 | protected Region(String name, Scope scope) { 15 | this.name = name; 16 | this.scope = scope; 17 | this.imexps = new ArrayList<>(); 18 | this.frame = null; 19 | } 20 | 21 | public abstract void gen(); 22 | 23 | public abstract ArrayList getEntries(); 24 | 25 | public abstract void insertEntry(Entry newEntry); 26 | } 27 | -------------------------------------------------------------------------------- /src/symbolstruct/Scope.java: -------------------------------------------------------------------------------- 1 | package symbolstruct; 2 | 3 | import global.Error; 4 | import symbolstruct.entries.AbsVarEntry; 5 | import symbolstruct.entries.Entry; 6 | import symbolstruct.entries.FuncEntry; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Objects; 10 | 11 | /** 12 | * Scope 作用域 13 | * 实际上是一个树节点 14 | * 存储了当前节点中所有的符号表项 15 | */ 16 | public class Scope { 17 | protected String name; 18 | protected Scope pre; 19 | protected ArrayList posts; 20 | protected final Integer level; 21 | private static Integer counter = 0; 22 | 23 | private ArrayList entries; 24 | private ArrayList params; 25 | 26 | public Scope(Integer level) { 27 | this.posts = new ArrayList<>(); 28 | this.pre = null; 29 | this.level = level; 30 | this.name = String.valueOf(Scope.counter++); 31 | this.entries = new ArrayList<>(); 32 | this.params = new ArrayList<>(); 33 | } 34 | 35 | protected void registerPara(Entry para) { 36 | para.isParam = true; 37 | this.params.add(para); 38 | } 39 | 40 | protected ArrayList getParams() { 41 | return this.params; 42 | } 43 | 44 | public ArrayList dumpAllEntries() { 45 | ArrayList ret = new ArrayList<>(); 46 | ret.addAll(this.entries); 47 | for (Scope child : this.posts) { 48 | ret.addAll(child.dumpAllEntries()); 49 | } 50 | return ret; 51 | } 52 | 53 | public ArrayList getNowEntries() { 54 | return entries; 55 | } 56 | 57 | protected Entry findVar(String name) { 58 | Scope tmpBlock = this; 59 | while (tmpBlock != null) { 60 | ArrayList tmpList = tmpBlock.entries; 61 | for (Entry entry : tmpList) { 62 | if (entry.name.equals(name) && entry instanceof AbsVarEntry) { 63 | return entry; 64 | } 65 | } 66 | tmpBlock = tmpBlock.pre; 67 | } 68 | Error.warning("Can't find the definition of " + name + " in " + this.name); 69 | return null; 70 | } 71 | 72 | protected Entry findFunc(String name) { 73 | Scope tmpBlock = this; 74 | while (tmpBlock != null) { 75 | ArrayList tmpList = tmpBlock.entries; 76 | for (Entry entry : tmpList) { 77 | if (entry.name.equals(name) && entry instanceof FuncEntry) { 78 | return entry; 79 | } 80 | } 81 | tmpBlock = tmpBlock.pre; 82 | } 83 | Error.warning("Can't find the definition of " + name + " in " + this.name); 84 | return null; 85 | } 86 | 87 | protected void insertEntry(Entry entry) { 88 | this.entries.add(entry); 89 | entry.in = this; 90 | } 91 | 92 | @Override 93 | public boolean equals(Object o) { 94 | if (this == o) return true; 95 | if (o == null || getClass() != o.getClass()) return false; 96 | Scope scope = (Scope) o; 97 | return Objects.equals(name, scope.name); 98 | } 99 | 100 | @Override 101 | public int hashCode() { 102 | return Objects.hash(name); 103 | } 104 | 105 | public Integer getLevel() { 106 | return level; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/symbolstruct/Symer.java: -------------------------------------------------------------------------------- 1 | package symbolstruct; 2 | 3 | import component.datatype.ArrayType; 4 | import component.datatype.Datatype; 5 | import component.datatype.IntType; 6 | import component.narray.NArray; 7 | import global.Error; 8 | import imcode.imexp.IMExp; 9 | import symbolstruct.entries.*; 10 | 11 | import java.util.ArrayList; 12 | 13 | /** 14 | * Scoper 15 | * 专用于管理Scope的结构, 16 | */ 17 | public class Symer { 18 | private Scope root; 19 | private Scope cur; 20 | 21 | public Symer() { 22 | this.root = null; 23 | this.cur = null; 24 | } 25 | 26 | public void pushScope() { 27 | Scope temp; 28 | if (this.root == null) { 29 | temp = new Scope(0); 30 | temp.pre = null; 31 | this.root = temp; 32 | } else { 33 | temp = new Scope(this.cur.level + 1); 34 | temp.pre = this.cur; 35 | this.cur.posts.add(temp); 36 | } 37 | this.cur = temp; 38 | } 39 | 40 | public void quitScope() { 41 | this.cur = this.cur.pre; 42 | } 43 | 44 | public Entry findVar(String name) { 45 | return this.cur.findVar(name); 46 | } 47 | 48 | public Entry findFunc(String name) { 49 | return this.root.findFunc(name); // 只有全局块,也就是root块才会有函数声明 50 | } 51 | 52 | public Entry insertVar(String name, Datatype type) { 53 | Entry ret = new VarEntry(name, type); 54 | this.cur.insertEntry(ret); 55 | return ret; 56 | } 57 | 58 | public Entry allocSpace(String name, Integer size) { 59 | Entry ret = new SpaceEntry(name, size); 60 | this.cur.insertEntry(ret); 61 | return ret; 62 | } 63 | 64 | public Entry insertArray(String name, Datatype type) { 65 | Entry ret = new ArrayEntry(name, type); 66 | this.cur.insertEntry(ret); 67 | return ret; 68 | } 69 | 70 | public Entry insertFunc(String name, Datatype type, ArrayList params) { 71 | Entry ret = new FuncEntry(name, type, params); 72 | this.cur.insertEntry(ret); 73 | return ret; 74 | } 75 | 76 | public Entry insertConstVar(String name, Datatype type, Integer value) { 77 | Entry ret = new ConstVarEntry(name, type, value); 78 | this.cur.insertEntry(ret); 79 | return ret; 80 | } 81 | 82 | public Entry insertConstArray(String name, Datatype type, NArray value) { 83 | Entry ret = new ConstArrayEntry(name, type, value); 84 | this.cur.insertEntry(ret); 85 | return ret; 86 | } 87 | 88 | public Entry insertParaVar(String name, Datatype type) { 89 | Entry ret = new VarEntry(name, type); 90 | this.cur.insertEntry(ret); 91 | this.cur.registerPara(ret); 92 | return ret; 93 | } 94 | 95 | public Entry insertParaArray(String name, Datatype type) { 96 | Entry ret = new ArrayEntry(name, type); 97 | this.cur.insertEntry(ret); 98 | this.cur.registerPara(ret); 99 | return ret; 100 | } 101 | 102 | public Scope getCur() { 103 | return cur; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/AbsVarEntry.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | import component.datatype.Datatype; 4 | 5 | import java.util.Objects; 6 | 7 | /** 8 | * 变量符号项父类 9 | * 包含数组变量和普通变量 10 | */ 11 | public abstract class AbsVarEntry extends Entry{ 12 | 13 | public Integer size; // 该符号表项所应该对应在栈帧中的长度,单位为字节 14 | 15 | protected AbsVarEntry(String name, Datatype datatype) { 16 | super(name, datatype); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/ArrayEntry.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | import component.datatype.ArrayType; 4 | import component.datatype.Datatype; 5 | 6 | public class ArrayEntry extends AbsVarEntry { 7 | 8 | public ArrayEntry(String name, Datatype datatype) { 9 | super(name, datatype); 10 | this.size = 1; 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return this.getClass().getSimpleName() + " " + this.datatype + " " + this.name; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/ConstArrayEntry.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | import component.datatype.Datatype; 4 | import component.narray.NArray; 5 | 6 | 7 | public class ConstArrayEntry extends ArrayEntry implements ConstFeature { 8 | public NArray value; 9 | 10 | public ConstArrayEntry(String name, Datatype type, NArray value) { 11 | super(name, type); 12 | this.value = value; 13 | this.size = 1; 14 | } 15 | 16 | @Override 17 | public Object getValue() { 18 | return this.value; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/ConstFeature.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | public interface ConstFeature { 4 | Object getValue(); 5 | } 6 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/ConstValueEntry.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | import component.datatype.IntType; 4 | 5 | import java.util.Objects; 6 | 7 | public class ConstValueEntry extends VarEntry implements ConstFeature { 8 | Integer value; 9 | 10 | public ConstValueEntry(Integer value) { 11 | super(String.valueOf(value), new IntType()); 12 | this.value = value; 13 | } 14 | 15 | @Override 16 | public Object getValue() { 17 | return value; 18 | } 19 | 20 | @Override 21 | public boolean equals(Object o) { 22 | if (this == o) return true; 23 | if (o == null || getClass() != o.getClass()) return false; 24 | if (!super.equals(o)) return false; 25 | ConstValueEntry that = (ConstValueEntry) o; 26 | return Objects.equals(value, that.value); 27 | } 28 | 29 | @Override 30 | public int hashCode() { 31 | return Objects.hash(this.getClass()) + Objects.hashCode(value); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/ConstVarEntry.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | import component.datatype.Datatype; 4 | 5 | public class ConstVarEntry extends VarEntry implements ConstFeature { 6 | private Integer value; 7 | 8 | public ConstVarEntry(String name, Datatype type, Object value) { 9 | super(name, type); 10 | this.value = (Integer) value; 11 | this.size = 1; 12 | } 13 | 14 | @Override 15 | public Object getValue() { 16 | return this.value; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/Entry.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | import component.datatype.Datatype; 4 | import symbolstruct.FuncRegion; 5 | import symbolstruct.Scope; 6 | import symboltable.Block; 7 | 8 | import java.util.Objects; 9 | 10 | public abstract class Entry { 11 | public String name; 12 | public Datatype datatype; 13 | public Scope in; 14 | public Boolean isParam; 15 | 16 | protected Entry(String name, Datatype datatype) { 17 | this.name = name; 18 | this.datatype = datatype; 19 | this.isParam = false; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | if (this == o) return true; 25 | if (o == null || getClass() != o.getClass()) return false; 26 | Entry entry = (Entry) o; 27 | return name.equals(entry.name) && Objects.equals(in, entry.in); 28 | } 29 | 30 | @Override 31 | public int hashCode() { 32 | int code = Objects.hash(name) + Objects.hash(in); 33 | return code; 34 | } 35 | 36 | public Boolean isGlobal() { 37 | return this.in.getLevel() == 0; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/FuncEntry.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | import component.datatype.Datatype; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class FuncEntry extends Entry { 8 | public ArrayList params; 9 | 10 | public FuncEntry(String name, Datatype datatype, ArrayList params) { 11 | super(name, datatype); 12 | this.params = params; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | StringBuilder temp = new StringBuilder(); 18 | for (Entry param : params) { 19 | temp.append(param.datatype.toString() + " "); 20 | } 21 | return this.datatype + " " + this.getClass().getSimpleName() + " (" + ")"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/SpaceEntry.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | public class SpaceEntry extends AbsVarEntry { 4 | public SpaceEntry(String name, Integer size) { 5 | super(name, null); 6 | this.size = size; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/symbolstruct/entries/VarEntry.java: -------------------------------------------------------------------------------- 1 | package symbolstruct.entries; 2 | 3 | import component.datatype.Datatype; 4 | import component.narray.NArrayItem; 5 | 6 | public class VarEntry extends AbsVarEntry implements NArrayItem { 7 | 8 | public VarEntry(String name, Datatype datatype) { 9 | super(name, datatype); 10 | this.size = 1; 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return this.getClass().getSimpleName() + " " + this.datatype + " " + this.name; 16 | } 17 | 18 | @Override 19 | public Object instance() { 20 | return this; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/symboltable/BasicType.java: -------------------------------------------------------------------------------- 1 | package symboltable; 2 | 3 | /** 4 | * BasicType 5 | * 作为SymbolItem对象成员 6 | * 表明该符号项的宏观类型 7 | * 比如一个返回值为int的函数,可以看做一个int值 8 | */ 9 | public enum BasicType { 10 | INT, 11 | VOID, 12 | STR, 13 | UNK, 14 | } 15 | -------------------------------------------------------------------------------- /src/symboltable/Block.java: -------------------------------------------------------------------------------- 1 | package symboltable; 2 | 3 | 4 | import exceptions.DuplicatedDefineException; 5 | import global.Config; 6 | import global.Error; 7 | import global.Logger; 8 | import symboltable.symbols.*; 9 | 10 | import java.util.ArrayList; 11 | import java.util.HashMap; 12 | 13 | 14 | /** 15 | * Block 16 | * 语法树节点 17 | * 表示一个作用域 18 | */ 19 | public class Block { 20 | public String name; // 作用域名称 21 | public BlockType type; // 作用域类型 22 | 23 | public Block pre; // 父作用域指针 24 | public ArrayList nexts; // 后继作用域指针 25 | 26 | public HashMap> items; // 该作用域下所有符号表项 27 | public HashMap statementCount; // 记录该作用域下各种语句的数量 28 | public SymbolItem funcHead; // 当前作用域如果是函数,则该变量是一个指向符号表中某函数表项的指针 29 | 30 | public Integer level; // 嵌套层次,设全局块的嵌套层次为0,依次递增 31 | public Boolean hasReturn; // 是否有返回值 32 | 33 | public Block(String name, BlockType type) { 34 | this.pre = null; 35 | this.nexts = new ArrayList<>(); 36 | this.items = new HashMap<>(); 37 | this.statementCount = new HashMap<>(); 38 | this.funcHead = null; 39 | this.name = name; 40 | this.type = type; 41 | this.hasReturn = false; 42 | } 43 | 44 | public void registerStatement(BlockType type) { 45 | if (!this.statementCount.containsKey(type)) { 46 | this.statementCount.put(type, 0); 47 | } 48 | this.statementCount.put(type, this.statementCount.get(type) + 1); 49 | } 50 | 51 | public SymbolItem findIdent(String name) { 52 | SymbolItem var = findVarAndConst(name, true); 53 | if (var != null) { 54 | var = findFunc(name, true); 55 | } 56 | return var; 57 | } 58 | 59 | public SymbolItem findIdentCurrent(String name) { 60 | SymbolItem var = findVarAndConst(name, false); 61 | if (var == null) { 62 | var = findFunc(name, false); 63 | } 64 | return var; 65 | } 66 | 67 | public SymbolItem findVarAndConst(String name, Boolean recur) { 68 | Block tmpBlock = this; 69 | 70 | while (tmpBlock != null) { 71 | ArrayList tmpList = tmpBlock.items.getOrDefault(SymbolItemType.VAR, new ArrayList<>()); 72 | for (SymbolItem item : tmpList) { 73 | if (item.name.equals(name)) { 74 | return item; 75 | } 76 | } 77 | 78 | ArrayList tmpArrayList = tmpBlock.items.getOrDefault(SymbolItemType.ARRAY, new ArrayList<>()); 79 | for (SymbolItem item : tmpArrayList) { 80 | if (item.name.equals(name)) { 81 | return item; 82 | } 83 | } 84 | 85 | tmpBlock = tmpBlock.pre; 86 | if (!recur) { 87 | break; 88 | } 89 | } 90 | return null; 91 | } 92 | 93 | public SymbolItem findFunc(String name, Boolean recur) { 94 | Block tmpBlock = this; 95 | 96 | while (tmpBlock != null) { 97 | ArrayList tmpList = tmpBlock.items.getOrDefault(SymbolItemType.FUNC, new ArrayList<>()); 98 | for (SymbolItem item : tmpList) { 99 | if (item.name.equals(name)) { 100 | return item; 101 | } 102 | } 103 | 104 | tmpBlock = tmpBlock.pre; 105 | if (!recur) { 106 | break; 107 | } 108 | } 109 | return null; 110 | } 111 | 112 | public void insertRecord(SymbolItem record) throws DuplicatedDefineException { 113 | SymbolItem item = this.findIdentCurrent(record.name); 114 | if (item == null) { 115 | if (!this.items.containsKey(record.itemType)) { 116 | this.items.put(record.itemType, new ArrayList<>()); 117 | } 118 | record.block = this; 119 | this.items.get(record.itemType).add(record); 120 | } else { 121 | throw new DuplicatedDefineException(); 122 | } 123 | } 124 | 125 | public void setFuncHead(SymbolItem funcHead) { 126 | if (this.funcHead != null) { 127 | Error.warning("You are changing the func head of an existing Block\'s func head!"); 128 | } 129 | if (!type.equals(BlockType.FUNC_BLOCK)) { 130 | Error.warning("You are setting a func head of an none-func block!"); 131 | } 132 | this.funcHead = funcHead; 133 | this.name = funcHead.name; 134 | } 135 | 136 | public SymbolItem createFunc(BasicType returnType, String name) throws DuplicatedDefineException { 137 | SymbolItem func = new FuncSymbolItem(returnType, name, this); 138 | this.insertRecord(func); 139 | return func; 140 | } 141 | 142 | public SymbolItem createConst(BasicType basicType, String name, Integer initVal) throws DuplicatedDefineException { 143 | SymbolItem const_ = new VarSymbolItem(true, basicType, name, this); 144 | ((VarSymbolItem) const_).setConstValue(initVal); 145 | this.insertRecord(const_); 146 | return const_; 147 | } 148 | 149 | public SymbolItem createVar(BasicType basicType, String name) throws DuplicatedDefineException { 150 | SymbolItem var = new VarSymbolItem(false, basicType, name, this); 151 | this.insertRecord(var); 152 | return var; 153 | } 154 | 155 | public SymbolItem createTemp(BasicType basicType, Boolean isConst) { 156 | SymbolItem temp = new VarSymbolItem(isConst, basicType, allocTempName(basicType.name()), this); 157 | try { 158 | this.insertRecord(temp); 159 | } catch (DuplicatedDefineException ignored) { 160 | ; 161 | } 162 | return temp; 163 | } 164 | 165 | public SymbolItem createConstArray(BasicType basicType, String name, ArrayList size, Object initVal) throws DuplicatedDefineException { 166 | ArraySymbolItem constArray = new ArraySymbolItem(true, basicType, name, this, size); 167 | constArray.setConstValue(initVal); 168 | this.insertRecord(constArray); 169 | return constArray; 170 | } 171 | 172 | public SymbolItem createVarArray(BasicType basicType, String name, ArrayList size) throws DuplicatedDefineException { 173 | ArraySymbolItem array = new ArraySymbolItem(false, basicType, name, this, size); 174 | this.insertRecord(array); 175 | return array; 176 | } 177 | 178 | public SymbolItem createTempArray(BasicType basicType, ArrayList size, Boolean isConst) { 179 | ArraySymbolItem array = new ArraySymbolItem(isConst, basicType, allocTempName(basicType.name()), this, size); 180 | try { 181 | this.insertRecord(array); 182 | } catch (DuplicatedDefineException ignored) { 183 | ; 184 | } 185 | return array; 186 | } 187 | 188 | public SymbolItem createStr(String name, String str) throws DuplicatedDefineException { 189 | SymbolItem var = new StrSymbolItem(allocTempName("str"), this, str); 190 | this.insertRecord(var); 191 | return var; 192 | } 193 | 194 | public SymbolItem createUnknown() { 195 | SymbolItem unk = new SymbolItem(BasicType.UNK, SymbolItemType.unknown, allocTempName("unknown"), this) { 196 | @Override 197 | public String type() { 198 | return "unknown"; 199 | } 200 | }; 201 | try { 202 | this.insertRecord(unk); 203 | } catch (DuplicatedDefineException ignored) { 204 | ; 205 | } 206 | return unk; 207 | } 208 | 209 | public SymbolItem createUnknownFunc() { 210 | SymbolItem unk = new FuncSymbolItem(BasicType.UNK, allocTempName("unknown"), this); 211 | try { 212 | this.insertRecord(unk); 213 | } catch (DuplicatedDefineException ignored) { 214 | ; 215 | } 216 | return unk; 217 | } 218 | 219 | public String allocTempName(String type) { 220 | return "#" + type + Config.getTmpNameSed(); 221 | } 222 | 223 | public void toLog() { 224 | for (SymbolItemType key : this.items.keySet()) { 225 | ArrayList items = this.items.get(key); 226 | for (SymbolItem item : items) { 227 | StringBuilder line = new StringBuilder(); 228 | for (int i = 0; i < level; i++) { 229 | line.append("\t"); 230 | } 231 | line.append(item.name + " " + item.type()); 232 | Logger.GetLogger().SymbolLog(line.toString()); 233 | } 234 | } 235 | for (Block block : this.nexts) { 236 | block.toLog(); 237 | } 238 | } 239 | 240 | /** 241 | * 找到当前块之前的最后一个函数块 242 | * 用于判断return语句的正确性 243 | * 因为会Block会嵌套很多层 244 | * 245 | * @return 最近一个父亲函数块Func_Block的返回类型 246 | */ 247 | public Block getLastFunc() { 248 | Block tmpBlock = this; 249 | 250 | while (tmpBlock != null && tmpBlock.funcHead == null) { 251 | tmpBlock = tmpBlock.pre; 252 | } 253 | if (tmpBlock == null) { 254 | return null; 255 | } else { 256 | return tmpBlock; 257 | } 258 | } 259 | 260 | public Boolean isInWhileBlock() { 261 | Block tmpBlock = this; 262 | 263 | while (tmpBlock != null && tmpBlock.type != BlockType.WHILE_BLOCK) { 264 | tmpBlock = tmpBlock.pre; 265 | } 266 | if (tmpBlock == null) { 267 | return false; 268 | } else { 269 | return true; 270 | } 271 | } 272 | 273 | public Boolean isInIfBlock() { 274 | Block tmpBlock = this; 275 | 276 | while (tmpBlock != null && tmpBlock.type != BlockType.WHILE_BLOCK) { 277 | tmpBlock = tmpBlock.pre; 278 | } 279 | if (tmpBlock == null) { 280 | return false; 281 | } else { 282 | return true; 283 | } 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /src/symboltable/BlockType.java: -------------------------------------------------------------------------------- 1 | package symboltable; 2 | 3 | public enum BlockType { 4 | IF_BLOCK, 5 | WHILE_BLOCK, 6 | NORMAL_BLOCK, 7 | FUNC_BLOCK, 8 | GLOBAL_BLOCK, 9 | } 10 | -------------------------------------------------------------------------------- /src/symboltable/SymbolItemType.java: -------------------------------------------------------------------------------- 1 | package symboltable; 2 | 3 | public enum SymbolItemType { 4 | unknown, 5 | FUNC, // 函数头 6 | VAR, // 变量 7 | STR, 8 | ARRAY, 9 | } 10 | -------------------------------------------------------------------------------- /src/symboltable/SymbolTable.java: -------------------------------------------------------------------------------- 1 | package symboltable; 2 | 3 | import global.Config; 4 | 5 | 6 | public class SymbolTable { 7 | public Block present; 8 | public Block root; 9 | 10 | public SymbolTable() { 11 | this.root = null; 12 | this.present = null; 13 | } 14 | 15 | public void addOneBlock(BlockType type) { 16 | Block temp; 17 | if (type.equals(BlockType.FUNC_BLOCK)) { 18 | temp = new Block("#unfilledFunc" + Config.getTmpNameSed(), type); 19 | } else if (type.equals(BlockType.IF_BLOCK)) { 20 | temp = new Block("#if" + Config.getTmpNameSed(), type); 21 | } else if (type.equals(BlockType.WHILE_BLOCK)) { 22 | temp = new Block("#while" + Config.getTmpNameSed(), type); 23 | } else if (type.equals(BlockType.GLOBAL_BLOCK)) { 24 | temp = new Block("#global", type); 25 | } else { 26 | temp = new Block("#normal" + Config.getTmpNameSed(), type); 27 | } 28 | 29 | if (type.equals(BlockType.GLOBAL_BLOCK)) { 30 | temp.level = 0; 31 | temp.pre = null; 32 | present = temp; 33 | if (root == null) { 34 | root = present; 35 | } 36 | } else { 37 | temp.level = present.level + 1; 38 | temp.pre = this.present; 39 | if (present != null) { 40 | present.nexts.add(temp); 41 | } 42 | present = temp; 43 | } 44 | } 45 | 46 | public void exitPresentBlock() { 47 | present = present.pre; 48 | } 49 | 50 | public Block getPresentBlock() { 51 | return this.present; 52 | } 53 | 54 | public void toLog() { 55 | this.root.toLog(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/symboltable/symbols/ArraySymbolItem.java: -------------------------------------------------------------------------------- 1 | package symboltable.symbols; 2 | 3 | import global.Error; 4 | import symboltable.BasicType; 5 | import symboltable.Block; 6 | import symboltable.SymbolItemType; 7 | 8 | import java.util.ArrayList; 9 | 10 | public class ArraySymbolItem extends SymbolItem { 11 | public Boolean isConst; 12 | private Object value; 13 | private ArrayList size; 14 | 15 | public ArraySymbolItem(Boolean isConst, BasicType dataType, String name, Block block, ArrayList size) { 16 | super(dataType, SymbolItemType.ARRAY, name, block); 17 | this.size = size; 18 | this.isConst = isConst; 19 | } 20 | 21 | public void setConstValue(Object value) { 22 | if (!isConst) { 23 | Error.warning("try to set value for an non-const array symbol"); 24 | } 25 | this.value = value; 26 | } 27 | 28 | public Integer getArrayLen(int dimension) { 29 | if (dimension >= size.size()) { 30 | return 0; // 0 表示该维度不存在 31 | } else { 32 | // size中可能有null值,表示该维度长度不定 33 | return size.get(dimension); 34 | } 35 | } 36 | 37 | public ArrayList getSize() { 38 | return size; 39 | } 40 | 41 | @Override 42 | public String type() { 43 | if (isConst) { 44 | if (size.size() == 1) { 45 | return "const int[]"; 46 | } else if (size.size() == 2) { 47 | return "const int[][]"; 48 | } else { 49 | Error.warning("wrong size of array item"); 50 | return "unknown"; 51 | } 52 | } else { 53 | if (size.size() == 1) { 54 | return "int[]"; 55 | } else if (size.size() == 2) { 56 | return "int[][]"; 57 | } else { 58 | Error.warning("wrong size of array item"); 59 | return "unknown"; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/symboltable/symbols/FuncSymbolItem.java: -------------------------------------------------------------------------------- 1 | package symboltable.symbols; 2 | 3 | import symboltable.BasicType; 4 | import symboltable.Block; 5 | import symboltable.SymbolItemType; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Locale; 9 | 10 | public class FuncSymbolItem extends SymbolItem { 11 | public ArrayList paramsList; 12 | 13 | public FuncSymbolItem(BasicType basicType, String name, Block block) { 14 | super(basicType, SymbolItemType.FUNC, name, block); 15 | } 16 | 17 | public void setParamsList(ArrayList paramsList) { 18 | this.paramsList = paramsList; 19 | } 20 | 21 | @Override 22 | public String type() { 23 | return this.dataType.toString().toLowerCase(Locale.ROOT) + " func"; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return type() + "\t" + name; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/symboltable/symbols/StrSymbolItem.java: -------------------------------------------------------------------------------- 1 | package symboltable.symbols; 2 | 3 | import symboltable.BasicType; 4 | import symboltable.Block; 5 | import symboltable.SymbolItemType; 6 | 7 | public class StrSymbolItem extends SymbolItem { 8 | 9 | private String content; 10 | 11 | public StrSymbolItem(String name, Block block, String content) { 12 | super(BasicType.STR, SymbolItemType.STR, name, block); 13 | this.content = content; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/symboltable/symbols/SymbolItem.java: -------------------------------------------------------------------------------- 1 | package symboltable.symbols; 2 | 3 | import symboltable.BasicType; 4 | import symboltable.Block; 5 | import symboltable.SymbolItemType; 6 | 7 | /** 8 | * SymbolItem 9 | * 符号表表项 10 | */ 11 | public abstract class SymbolItem { 12 | public BasicType dataType; // 数据类型 13 | public SymbolItemType itemType; // 符号项类型 14 | public String name; // 符号项名称 15 | public Block block; //所处的Block对象 16 | 17 | protected SymbolItem(BasicType dataType, SymbolItemType itemType, String name, Block block) { 18 | this.dataType = dataType; 19 | this.itemType = itemType; 20 | this.name = name; 21 | this.block = block; 22 | } 23 | 24 | public String type(){ 25 | return "unknown"; 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/symboltable/symbols/VarSymbolItem.java: -------------------------------------------------------------------------------- 1 | package symboltable.symbols; 2 | 3 | import global.Error; 4 | import symboltable.BasicType; 5 | import symboltable.Block; 6 | import symboltable.SymbolItemType; 7 | 8 | import java.util.ArrayList; 9 | 10 | public class VarSymbolItem extends SymbolItem { 11 | 12 | public Boolean isConst; 13 | public Object constValue; 14 | 15 | public VarSymbolItem(Boolean isConst, BasicType basicType, String name, Block block) { 16 | super(basicType, SymbolItemType.VAR, name, block); 17 | this.isConst = isConst; 18 | this.constValue = null; 19 | } 20 | 21 | public Object getConstValue() { 22 | if (!isConst) { 23 | Error.warning(" <" + this.name + ">try to get value from a non-const var! (const[] element is also non-const!)"); 24 | } 25 | return constValue; 26 | } 27 | 28 | public void setConstValue(Integer constValue) { 29 | if (this.constValue != null) { 30 | Error.warning(" <" + this.name + "> try to set value for a var that already has a const value"); 31 | } 32 | if (!isConst) { 33 | Error.warning(" <" + this.name + ">try to set value for a non-const var! (const[] element is also non-const!)"); 34 | } 35 | this.constValue = constValue; 36 | } 37 | 38 | @Override 39 | public String type() { 40 | if (!isConst) { 41 | return "int"; 42 | } else { 43 | return "const int"; 44 | } 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return type() + "\t" + name; 50 | } 51 | } 52 | --------------------------------------------------------------------------------