├── .gitignore ├── README.md ├── report ├── 0-summary.tex ├── 1-lexer.tex ├── 2-parser.tex ├── 3-semanic.tex ├── 4-midcode.tex ├── 5-target.tex ├── 6-optimize.tex ├── 7-end.tex ├── img │ ├── expr.drawio │ ├── stack.drawio │ ├── summary.drawio │ ├── translator.drawio │ └── tree.drawio ├── main.aux ├── main.out ├── main.tex ├── main.toc ├── 结语.md └── 编译实验设计报告.pdf ├── src ├── Compiler.java ├── back │ ├── MipsObject.java │ ├── RegMap.java │ ├── Translator.java │ ├── hardware │ │ ├── Memory.java │ │ ├── RF.java │ │ └── Reg.java │ ├── instr │ │ ├── Addiu.java │ │ ├── Addu.java │ │ ├── Beq.java │ │ ├── Bne.java │ │ ├── Div.java │ │ ├── J.java │ │ ├── Jal.java │ │ ├── Jr.java │ │ ├── La.java │ │ ├── Lb.java │ │ ├── Lh.java │ │ ├── Li.java │ │ ├── Lw.java │ │ ├── Mfhi.java │ │ ├── Mflo.java │ │ ├── MipsInstr.java │ │ ├── Move.java │ │ ├── Mul.java │ │ ├── Mult.java │ │ ├── Nop.java │ │ ├── Sb.java │ │ ├── Seq.java │ │ ├── Sge.java │ │ ├── Sgt.java │ │ ├── Sh.java │ │ ├── Sle.java │ │ ├── Sll.java │ │ ├── Slt.java │ │ ├── Slti.java │ │ ├── Sltu.java │ │ ├── Sne.java │ │ ├── Sra.java │ │ ├── Srl.java │ │ ├── Subiu.java │ │ ├── Subu.java │ │ ├── Sw.java │ │ ├── Syscall.java │ │ ├── Xor.java │ │ └── Xori.java │ └── optimize │ │ └── MultDiv.java ├── exception │ ├── CompileExc.java │ └── LexerExc.java ├── front │ ├── CompileUnit.java │ ├── FuncEntry.java │ ├── Lexer.java │ ├── Parser.java │ ├── SemanticChecker.java │ ├── SymbolTable.java │ ├── TableEntry.java │ ├── Token.java │ ├── TokenPackage.java │ └── nodes │ │ ├── AssignNode.java │ │ ├── BinaryExpNode.java │ │ ├── BlockItemNode.java │ │ ├── BlockNode.java │ │ ├── BreakStmtNode.java │ │ ├── CompileUnitNode.java │ │ ├── ContinueStmtNode.java │ │ ├── DeclNode.java │ │ ├── DefNode.java │ │ ├── EmptyStmtNode.java │ │ ├── ExprNode.java │ │ ├── FuncCallNode.java │ │ ├── FuncDefNode.java │ │ ├── FuncParamNode.java │ │ ├── GetintNode.java │ │ ├── IfNode.java │ │ ├── LValNode.java │ │ ├── NumberNode.java │ │ ├── PrintfNode.java │ │ ├── ReturnNode.java │ │ ├── StmtNode.java │ │ ├── SyntaxNode.java │ │ ├── UnaryExpNode.java │ │ └── WhileNode.java ├── mid │ ├── IrModule.java │ ├── LabelCounter.java │ ├── MidCodeGenerator.java │ ├── StringCounter.java │ ├── TempCounter.java │ ├── ircode │ │ ├── BasicBlock.java │ │ ├── BinaryOperator.java │ │ ├── Branch.java │ │ ├── Call.java │ │ ├── ElementPtr.java │ │ ├── FuncDef.java │ │ ├── Immediate.java │ │ ├── Input.java │ │ ├── InstructionLinkNode.java │ │ ├── Jump.java │ │ ├── Operand.java │ │ ├── PointerOp.java │ │ ├── PrintInt.java │ │ ├── PrintStr.java │ │ ├── Return.java │ │ ├── UnaryOperator.java │ │ ├── User.java │ │ ├── Value.java │ │ └── VarDef.java │ └── optimize │ │ ├── ColorResult.java │ │ ├── ColorScheduler.java │ │ ├── ConstantPropagation.java │ │ ├── CopyPropagation.java │ │ ├── DeadCodeKiller.java │ │ ├── FlowGraphBuilder.java │ │ ├── IrOptimizer.java │ │ ├── LiveVariableAnalyser.java │ │ ├── LiveVariableTable.java │ │ ├── Peephole.java │ │ ├── ReachingDefAnalyser.java │ │ ├── ReachingDefTable.java │ │ ├── Util.java │ │ └── Value.java └── util │ └── Pair.java ├── test ├── test-exam.py ├── test-mips.py └── test.py └── testfiles ├── input1.txt ├── input2.txt ├── input3.txt ├── input4.txt ├── input5.txt ├── output1.txt ├── output2.txt ├── output3.txt ├── output4.txt ├── output5.txt ├── testfile1.txt ├── testfile2.txt ├── testfile3.txt ├── testfile4.txt └── testfile5.txt /README.md: -------------------------------------------------------------------------------- 1 | # SysY-MIPS-Compiler 2 | 北航计算机学院2022秋季编译课设,一个SysY到MIPS的玩具编译器 3 | ## 文件结构说明 4 | * report目录中为项目报告,Latex编写 5 | * src目录中为源代码 6 | * test目录中为本地评测脚本 7 | ## 编译器说明 8 | * 语法分析采用递归下降 9 | * 中间代码采用类似llvm的形式 10 | * 其他详细说明见文档 11 | ## 实现的优化 12 | (具体有没有效果未可知,详细说明见文档) 13 | * 窥孔优化 14 | * 常量传播 15 | * 复写传播 16 | * 死代码删除 17 | * 循环结构优化 18 | * 图着色寄存器分配 19 | * 指令选择优化 20 | * 乘除优化 21 | -------------------------------------------------------------------------------- /report/0-summary.tex: -------------------------------------------------------------------------------- 1 | \chapter{总体架构} 2 | 本编译器的总体架构如\ref{fig:summary}。 3 | 4 | \begin{figure}[htbp] 5 | \centering 6 | \includegraphics[width=0.8\linewidth]{img/summary.png} 7 | \caption{编译器总体架构} 8 | \label{fig:summary} 9 | \end{figure} 10 | 11 | 本编译器由以下几个主要模块组成 12 | \begin{itemize} 13 | \item 词法分析器:读入源代码,进行词法分析,输出一个token流。 14 | \item 语法分析器:利用语法分析器递归下降分析token流,得到具体语法树,遇到错误时添加到全局错误表。 15 | \item 语义分析器:利用语义分析器进行符号表的管理,并得到抽象语法树,遇到错误时添加到全局错误表。 16 | \item 中间代码生成器及优化器:得到抽象语法树后根据不同的语法节点类型生成llvm中间代码,并且可以配置是否开启优化。 17 | \item 目标代码生成器及优化器:通过llvm中间代码生成mips目标代码,可以配置选择是否开启优化。 18 | \end{itemize} 19 | 20 | 随后的章节将会介绍这些模块的设计细节。 21 | 22 | 23 | -------------------------------------------------------------------------------- /report/1-lexer.tex: -------------------------------------------------------------------------------- 1 | \chapter{词法分析} 2 | \section{设计概述} 3 | 词法分析的任务是设计有限状态机,读取源代码并将其划分成一个个的终结符,即单词(Token),并过滤注释。 4 | 5 | 在具体实现方面,本编译器采用了正则表达式提前捕获组的方式提取并分割单词,具体步骤如下: 6 | \begin{enumerate} 7 | \item 首先对于每种单词,均构造一个正则表达式。\\例如\texttt{MAINTK\_P = "(?main(?![a-zA-Z0-9\_]))"}。 8 | \\同时,对于空白符、单行注释和多行注释,也需要构造相应的正则表达式。 9 | \item 将每种单词的正则表达式连接起来,形成一个总体正则表达式,并分配进入第一个匹配的捕获组。 10 | \item 利用\texttt{Matcher.group}判断单词的类型,并获取具体单词内容即可。 11 | \end{enumerate} 12 | 13 | 并且词法分析时,还需要得到单词的行号,为错误处理提供信息基础,本编译器通过记录读入到的\texttt{\ n}的数量来记录行号。 14 | 15 | 最后经过词法分析,本编译器将得到一个包含所有单词的有序列表\texttt{List},按照符合要求的方式输出即可。 16 | \section{编码后的修改} 17 | 采用正则表达式匹配的方法来进行词法分析较容易出错的点是捕获顺序,这个在设计时很容易忽略,在调试时发现。 18 | 例如 19 | \begin{enumerate} 20 | \item \texttt{==}这类包括多个字符的单词应该排序在总体正则表达式靠前于\texttt{=}的位置,不然\texttt{==}会首先被\texttt{ASSIGN}捕获组捕获,从而得到两个\texttt{ASSIGN}而不是一个\texttt{EQL} 21 | \item \texttt{MAINTK}这类关键字同时也满足表示符的正则表达式,因此关键字的正则表达式应优先于表示符的正则表达式。 22 | \item 正则表达式还面临优化问题,过于复杂的正则表达式可能会造成栈溢出,例如对于多行注释的识别, 23 | 若表达式为\texttt{"/*(.|$\backslash$ n|$\backslash$ r)*?*/"},则会因为存在不确定的匹配导致在处理较长注释时,发生栈溢出错误,将表达式优化为\texttt{"/*[$\backslash$ s$\backslash$ S]*?*/"}消除不确定的匹配即可解决问题。 24 | \end{enumerate} 25 | 26 | 这些问题在具体编码时随调试逐步完成正确。 -------------------------------------------------------------------------------- /report/2-parser.tex: -------------------------------------------------------------------------------- 1 | \chapter{语法分析} 2 | \section{设计概述} 3 | 语法分析的任务是遍历词法分析得到的单词有序表,根据给定的形式文法,分析并确定其语法结构。 4 | 5 | 本编译器采用了递归下降的方法进行语法分析,采用语法树这种层次化的结构保存语法分析的结果, 6 | 单词有序表经过语法分析后,将得到一个完全符合课程给出文法的具体语法树。 7 | 为了避免过于冗余的代码以及满足语法分析的输出要求,本编译器在本阶段的语法分析中, 8 | 得到的所有语法成分(终结符以及非终结符)均采用统一的\texttt{CompileUnit}类来表示, 9 | 通过\texttt{CompileUnit}类中的\texttt{name}和\texttt{type}来区分不同的成分, 10 | 用\texttt{isEnd}成员来标记是否为终结符。类的定义如下。 11 | \begin{minted}{java} 12 | public class CompileUnit { 13 | private final String name;//若为非终结符,则为类型名,否则为终结符内容 14 | private final Type type;//语法成分类型 15 | private final List childUnits;//语法子树 16 | private final boolean isEnd;//是否是终结符 17 | private final Integer lineNo;//若为终结符,则需要有行号 18 | ... 19 | } 20 | \end{minted} 21 | 22 | \section{设计细节} 23 | 24 | \subsection{文法左递归处理} 25 | 文法左递归会给自顶向下的递归下降语法分析方法带来无限递归或不可避免的回溯问题,因此需要对文法进行BNF范式改写。 26 | 文法中的左递归主要出现在表达式部分,以\texttt{AddExp}为例,\newline 27 | \texttt{AddExp → MulExp |AddExp ('+' | '−') MulExp } 可以改写为 28 | 29 | \texttt{AddExp → MulExp { ('+' | '−') MulExp}}。其他表达式相关文法均按照类似方法消除左递归。 30 | 31 | 需要注意的是,语法分析作业需要检查语法成分的输出顺序。由于改写文法的同时也造成语法树的改动,即由二叉树转化成了多叉树,因此这种改动可能会造成输出顺序与要求不同, 32 | 所以还需要将识别到的语法成分转化回原来的语法树结构。仍以\texttt{AddExp}为例,具体方法是每当读到一个\texttt{+/-}时,就将读到加减号前的语法结构向上打包成一个新的\texttt{AddExp}, 33 | 这样在输出时就不会由于多叉树公用根的问题导致缺少输出了。 34 | 35 | \subsection{赋值语句与表达式语句区分问题} 36 | 37 | 文法中的\texttt{Stmt → LVal '=' Exp ';' }和\texttt{Stmt → [Exp] ';'}的FIRST都有可能是\texttt{LVal},因此只向前看一个字符很难确定要用使用什么规则递归下降, 38 | 为了较好的和原语法树结构相符,此处本编译器没有做特殊处理,而是采用向前看两个符号的方法, 39 | 先尝试读入一个\texttt{LVal},若能读入一个\texttt{LVal},则看下一个词法成分是否是\texttt{=},如果是,则为赋值语句。 40 | 41 | \subsection{为错误处理预留接口} 42 | 43 | 在进行语法分析设计时,为错误处理预留了接口,当解析到不符合文法规则的成分时,会抛出异常。 44 | 45 | \section{编码后的修改} 46 | 47 | \begin{enumerate} 48 | \item 在初次实现时,判断应用哪条规则时采用了当前符号“不是...”判断,比如当前不是分号,就继续读入\texttt{LVal}等, 49 | 这样的设计在错误处理中带来了问题,因为被用来判断的符号可能缺少,例如缺分号错误,导致程序出错。因此在最后 50 | 判断条件都改为了当前词法元素“是...”来判断。 51 | \end{enumerate} -------------------------------------------------------------------------------- /report/3-semanic.tex: -------------------------------------------------------------------------------- 1 | \chapter{语义分析和错误处理} 2 | \section{设计概述} 3 | 4 | 错误处理中的错误分为两大类,语法错误和语义错误,因此本编译器在语法分析和语义分析两个阶段分别处理这两种不同的错误,并将错误添加到全局错误表。 5 | 6 | 在之前的语法分析过程中,我们已经得到具体语法树,但是由于具体语法树上的所有节点的类都是\texttt{CompileUnit},并且具体语法树上还有类似于 7 | \texttt{"(", ";"}等与后续分析无关的符号,这会给后续的代码生成带来不便。同时,原文法中涉及到的表达式类型繁多,但其实均可以归为二元运算和一元运算两类。 8 | 因此在语义分析阶段,语义分析器将读入具体语法树,并进行语义分析,输出抽象语法树,如果发现语义错误,则将错误加入全局错误表。 9 | 10 | \section{设计细节} 11 | \subsection{语法错误处理} 12 | 13 | 在所有错误类型中,语法错误如表\ref{table:syntax} 14 | 15 | \begin{table}[H] 16 | \centering 17 | \begin{tabular}{cc} 18 | \toprule 19 | 错误类型 & 错误类别码 \\ 20 | \midrule 21 | 非法符号 & a \\ 22 | 缺少分号 & i \\ 23 | 缺少右小括号')' & j\\ 24 | 缺少右中括号']' & k \\ 25 | \bottomrule %添加表格底部粗线 26 | \end{tabular} 27 | \caption{语法错误表} 28 | \label{table:syntax} 29 | \end{table} 30 | 31 | 语法错误发现和处理比较容易,当语法分析器判断当前应当读入一个分号,右小括号,右中括号但没有读到时,就可以判断发生了错误,并将错误添加到全局错误表, 32 | 之后跳过这个待读入符号继续语法分析。非法符号错误则不影响整体的具体语法树,只需要在读到\texttt{FormatString}时单独检查即可。 33 | \subsection{语义分析与语义错误处理} 34 | 在所有错误类型中,语义错误如表\ref{table:syntax} 35 | 36 | \begin{table}[H] 37 | \centering 38 | \begin{tabular}{cc} 39 | \toprule 40 | 错误类型 & 错误类别码 \\ 41 | \midrule 42 | 名字重定义 & b \\ 43 | 未定义的名字 & c \\ 44 | 函数参数个数不匹配 & d\\ 45 | 函数参数类型不匹配 & e \\ 46 | 无返回值的函数存在不匹配的return语句 & f\\ 47 | 有返回值的函数缺少return语句 & g\\ 48 | 不能改变常量的值 &h\\ 49 | printf中格式字符与表达式个数不匹配 & l \\ 50 | 在非循环块中使用break和continue语句 & m\\ 51 | \bottomrule %添加表格底部粗线 52 | \end{tabular} 53 | \caption{语义错误表} 54 | \label{table:syntax} 55 | \end{table} 56 | 57 | 语义分析的总体过程是遍历具体语法树,在过程中维护符号表和全局函数表从而完成错误处理,并在过程中将具体语法树的节点转化为抽象语法树的节点。 58 | 59 | l类错误较为简单,对于m类型错误,在语义分析时需要在分析到循环类stmt的时候记录循环深度,若在循环深度为0时出现了break或continue语句,则发生m类错误。 60 | 61 | 除了最后两种错误外,其他的所有错误都和符号表操作相关,实质上是对符号表进行查找并进行判断,完成符号表设计后,错误处理也就基本完成了。 62 | \subsection{符号表设计} 63 | 本编译器在语义分析阶段维护两张表,分别是变量表和全局函数表。 64 | 65 | 全局函数表较为简单,是一个以函数名作为键,表项作为值的哈希表。 66 | 67 | 其中变量表采用树形结构,抽象语法树中的每个\texttt{block}保存其对应的变量表。 68 | 树形符号表的结构图为\ref{fig:tree} 69 | \begin{figure}[htbp] 70 | \centering 71 | \includegraphics[width=0.8\linewidth]{img/tree.png} 72 | \caption{树形符号表结构图} 73 | \label{fig:tree} 74 | \end{figure} 75 | 76 | 每个代码块保存指向子表的指针,每个子表都保存一个指向其父表的指针,查找符号表时,先查找本符号表,若没有查到,则递归的查找父符号表,直到查找到最外层的全局变量表。 77 | 树形符号表与栈式符号表相比的优点在于,栈式符号表在每个\texttt{block}分析结束后会被弹出删除,没有保存分析结果和维护符号表之间的层次关系, 78 | 树形符号表则可以保存这次语义分析的结果,从而在后续代码生成时继续使用。 79 | 80 | 81 | 82 | 变量表的表项设计为 83 | \begin{minted}{java} 84 | public class TableEntry implements Operand { 85 | public final RefType refType; //包括ITEM-普通变量,ARRAY-数组,POINTER-指针,三种类型 86 | public final ValueType valueType; //包括INT-整数,VOID-空,两种类型 87 | public final String name;//变量名 88 | public ExprNode initValue;//初始值 89 | public List initValueList;//数组初始值 90 | public List dimension;//数组每一维的大小 91 | public final int level;//定义处的层数 92 | public final boolean isConst;//是否是常量 93 | public final boolean isGlobal;//是否是全局变量 94 | public boolean isParameter; //是否是函数参数; 95 | ... 96 | } 97 | \end{minted} 98 | 99 | 函数表的表项设计为 100 | \begin{minted}{java} 101 | public class FuncEntry { 102 | private final String name;//函数名 103 | private final List args = new ArrayList<>();//参数表 104 | private final Map name2entry = new HashMap<>();//参数表 105 | private final boolean isMain;//是否是主函数 106 | private final TableEntry.ValueType returnType;//返回值类型 107 | ... 108 | } 109 | \end{minted} 110 | 111 | \section{编码后的修改} 112 | 113 | \begin{enumerate} 114 | \item 在解析完函数头之后应该立即将函数表项加入全局函数表,不然函数递归调用的时候会报未定义名字的错误。 115 | \item 初次实现的时候函数参数没有加入符号表导致误报未定义名字错误。 116 | \item 全局变量和函数不能重名,而局部变量和函数可以重名,这里需要特殊处理。 117 | \end{enumerate} -------------------------------------------------------------------------------- /report/4-midcode.tex: -------------------------------------------------------------------------------- 1 | \chapter{中间代码生成} 2 | \section{设计概述} 3 | 4 | 中间代码生成的任务是将树状结构的抽象语法树,转化成线性结构的中间代码序列。本编译器的中间代码采用了llvm中间代码。 5 | 6 | 本编译器将中间代码分为了12类,如表\ref{table:midcode}。 7 | 8 | 生成中间代码的过程就是遍历抽象语法树,并将语法树中嵌套的\texttt{block}转化成中间代码中线性的\texttt{basicBlock}。 9 | 10 | 划分基本块有助于将嵌套结构转化成线性,因此本编译器在此阶段完成基本块划分,也为之后代码优化打基础。 11 | 12 | 保存中间代码的数据结构方面,采用了链表来保存中间代码序列, 13 | 便于后续在代码优化阶段会频繁的发生代码的增删,替换操作。 14 | 15 | \begin{table}[H] 16 | \centering 17 | \begin{tabular}{ccc} 18 | \toprule 19 | 类型 & 意义 & 样例 \\ 20 | \midrule 21 | funcDef & 函数定义 & \texttt{define i32 @fib(i32 \%i\_1)} \\ 22 | VarDef & 变量定义 & \texttt{\%i\_1 = alloca i32} \\ 23 | BinaryOperator & 二元运算 & \texttt{\%-t15\_0 = mul i32 \%-t13\_0, \%-t14\_0}\\ 24 | UnaryOperator & 一元运算 & 转化为二元形式输出 \\ 25 | Branch & 分支 & \texttt{ br \%-t106\_0 label \%label\_11 label \%label\_9}\\ 26 | Jump & 跳转 & \texttt{br label \%while\_cond\_label\_10 }\\ 27 | Call & 函数调用 &\texttt{\%-t7\_0 = call i32 @fib(i32 \%-t9\_0) }\\ 28 | ElementPtr & 数组寻址 &\texttt{getelementptr [10 x i32], [10 x i32]* @a, i32 0, i32 1 }\\ 29 | PointerOp & 内存操作(存取)&\texttt{\%-t35\_0 = load i32, i32* \%k\_1 }\\ 30 | Return & 返回 &\texttt{ret i32 0 } \\ 31 | PrintInt & 输出整数 & \texttt{call void @putint(i32 \%-t109\_0 ) }\\ 32 | PrintStr & 输出字符串 & \texttt{ call void @putch(i32 44 ) ; ','}\\ 33 | \bottomrule %添加表格底部粗线 34 | \end{tabular} 35 | \caption{中间代码表} 36 | \label{table:midcode} 37 | \end{table} 38 | 39 | \section{设计细节} 40 | 41 | \subsection{变量的定义和初始化} 42 | 43 | 对于全局变量,加入中间代码的全局变量列表,并将符号表表项中的\texttt{isDefined}设置为\texttt{true}。 44 | 45 | 对于局部变量,在代码序列中加入一个\texttt{VarDef},并将符号表表项中的\texttt{isDefined}设置为\texttt{true}。 46 | 47 | 对于数组,由于数组的维数定义目前还是常量表达式,需要对数组维度定义进行常量表达式化简。 48 | 49 | 对于初始值,普通变量的初始值只有一个,在进行常量表达式化简后,在代码序列中加入一个\texttt{STORE}即可。数组变量的初值 50 | 由于存在嵌套,需要用广度优先遍历得到线性的初值序列,然后通过\texttt{STORE}依次赋值。 51 | 52 | 对于常量,非数组类的常量都可以在此阶段直接替换为数,不用再以变量的形式出现,因此中间代码中不会出现对于非数组类常量的定义。 53 | 数组类常量则是可以在此阶段直接确定通过下标访问值,但是对于通过变量访问的值则无法确定,因此仍然需要出现在中间代码中。 54 | 55 | 样例: 56 | \begin{minted}{java} 57 | %i_1 = alloca i32 58 | store i32 2, i32* %i_1 59 | \end{minted} 60 | 61 | \subsection{变量的访问和赋值} 62 | 变量表的表项掌握着变量的所有相关信息,因此可以直接将变量表的表项当作变量使用。 63 | 由于中间代码阶段还没有寄存器分配,目前所有的变量都分配在内存上,因此对变量的访问和赋值都需要通过\texttt{PointerOp(STORE,LOAD)}进行。 64 | 不同层定义的同名变量本质上是不同的变量,因此应该加以区分,同时也方便之后的代码优化, 65 | 因此需要重写变量表表项的\texttt{Equal}方法,将名字和层数都相等的变量视为同一个变量。 66 | 67 | \begin{minted}{java} 68 | public boolean equals(Object o) { 69 | if (this == o) return true; 70 | if (o == null || getClass() != o.getClass()) return false; 71 | TableEntry that = (TableEntry) o; 72 | return level == that.level && Objects.equals(name, that.name); 73 | } 74 | \end{minted} 75 | 76 | 变量的访问需要先通过符号表查找被标记为\texttt{isDefined}的变量, 77 | 然后新增一个临时变量来保存变量的值,在代码序列中加入一个\texttt{PointerOp(LOAD)},返回这个临时变量。 78 | 79 | 对变量的赋值可以是赋值一个立即数,也可以赋值一个临时变量中保存的结果,先通过符号表查找被标记为\texttt{isDefined}的变量, 80 | 然后在代码序列中加入一个\texttt{PointerOp(STORE)}。 81 | 82 | \subsection{表达式计算} 83 | 84 | 首先表达式可以先经过一次常量化简,将常量都替换成立即数。 85 | 表达式计算的基本逻辑是将已有的变量或立即数作为操作数,然后新增一个临时变量来存放表达式的计算结果,并返回这个存结果的临时变量。 86 | 调用时,递归地调用即可。 87 | 88 | 抽象语法树赋值语句表达式转化为中间代码的过程大致如图\ref{fig:expr}。 89 | 90 | \begin{figure}[htbp] 91 | \centering 92 | \includegraphics[width=0.8\linewidth]{img/expr.png} 93 | \caption{表达式转化为中间代码过程} 94 | \label{fig:expr} 95 | \end{figure} 96 | 97 | \subsection{控制流(循环和分支)} 98 | \subsubsection{分支} 99 | 对于分支,也就是\texttt{if else}语句: 100 | 101 | \begin{minted}{java} 102 | if(cond){ 103 | //ifStmt 104 | }else{ 105 | //elseStmt 106 | } 107 | //end, new basicBlock 108 | \end{minted} 109 | 按照如下方式生成 110 | 111 | \begin{minted}{java} 112 | temp = cond;//temp保存表达式cond的计算结果 113 | br temp label ifStmt_label label elseStmt_label 114 | elseStmt_label: 115 | //elseStmt 116 | br label newBasicBlock_label 117 | ifStmt_label: 118 | //ifStmt 119 | newBasicBlock_label: 120 | //end, new basicBlock 分支结束,新增基本块 121 | \end{minted} 122 | 123 | \subsubsection{循环} 124 | 对于如下循环: 125 | \begin{minted}{java} 126 | while(cond){ 127 | //whileStmt 128 | } 129 | //end, new basicBlock 130 | \end{minted} 131 | 132 | 按照如下方式生成 133 | 134 | \begin{minted}{java} 135 | whileCond_begin: 136 | temp = cond;//temp保存表达式cond的计算结果 137 | br temp label whileBody_begin label newBasicBlock_label 138 | whileBody_begin: 139 | //whileStmt 140 | br label whileCond_begin 141 | newBasicBlock_label: 142 | //end, new basicBlock 循环结束,新增基本块 143 | \end{minted} 144 | 145 | \subsection{数组的访问} 146 | 数组的访问需要先通过一条\texttt{ElementPtr}计算出指向访问位置的地址,再通过\texttt{PointerOp}来存取数组中的值。 147 | 148 | 此处需要注意的是普通数组和函数参数中的数组访问有所区别。 149 | 函数参数中的数组的第一维度信息缺失,实质上是一个指向原数组的指针,比数组少一维。 150 | 151 | \subsection{短路求值} 152 | 153 | \subsubsection{分支的\&\&短路} 154 | 分支的\&\&短路可以变换为 155 | \begin{minted}{java} 156 | //变换前 157 | if (a && b) { 158 | //ifStmt 159 | } else { 160 | //elseStmt 161 | } 162 | //变换后 163 | if (a) { 164 | if (b){ 165 | //ifStmt 166 | } else { 167 | //elseStmt 168 | } 169 | } else { 170 | //elseStmt 171 | } 172 | 173 | \end{minted} 174 | 175 | 176 | \subsubsection{分支的||短路} 177 | 178 | 分支的||短路可以变换为 179 | \begin{minted}{java} 180 | //变换前 181 | if (a || b) { 182 | //ifStmt 183 | } else { 184 | //elseStmt 185 | } 186 | //变换后 187 | if (a) { 188 | //ifStmt 189 | } else { 190 | if (b){ 191 | //ifStmt 192 | } else { 193 | //elseStmt 194 | } 195 | } 196 | 197 | \end{minted} 198 | 199 | 200 | \subsubsection{循环的短路} 201 | 202 | 若循环存在短路求值,则可进行以下转化 203 | \begin{minted}{java} 204 | //变换前 205 | while (cond) { 206 | //whileStmt 207 | } 208 | //变换后 209 | while (1) { 210 | if (cond) { 211 | //whileStmt 212 | } else { 213 | break; 214 | } 215 | } 216 | \end{minted} 217 | 218 | 219 | \section{编码后的修改} 220 | 由于中间代码的设计不同,代码生成的实现方式非常多样,因此此处的bug大多都是个性问题,数量多且关乎细节,此处抽象的列举几处修改。 221 | \begin{enumerate} 222 | \item printf中参数的计算和字符串输出顺序问题,应先算完所有的参数再一起输出, 223 | 不然可能会出现参数中包含函数调用,输出内容被函数内的输出阻断的效果。 224 | \item 短路求值转化时block种类问题。 225 | \item 短路求值转化时符号表问题。 226 | \item 短路求值转化未将后续使用的node替换为转化后的node导致条件丢失。 227 | \item 定义使用顺序问题,使用了本层后续定义的变量。 228 | \end{enumerate} -------------------------------------------------------------------------------- /report/5-target.tex: -------------------------------------------------------------------------------- 1 | \chapter{目标代码生成} 2 | \section{设计概述} 3 | 4 | 此阶段将体系结构无关的中间代码翻译成MIPS体系结构的目标代码。程序的控制流,计算指令等已经在中间代码生成阶段完成, 5 | 对于单条中间代码如何翻译成目标代码难度不大。目标代码生成的难点主要集中在寄存器分配和管理,运行时的存储管理,切换和恢复运行现场。 6 | 7 | 本编译器生成目标代码的流程如图\ref{fig:translator}。 8 | 9 | \begin{figure}[htbp] 10 | \centering 11 | \includegraphics[width=0.8\linewidth]{img/translator.png} 12 | \caption{生成目标代码基本流程} 13 | \label{fig:translator} 14 | \end{figure} 15 | 16 | 大致步骤如下: 17 | \begin{enumerate} 18 | \item 首先将要输出的字符串填在data段,设置全局变量初值并设置全局指针\texttt{\$gp}和帧指针\texttt{\$fp}。 19 | \item 随后生成函数体代码,在函数入口处需要计算并分配函数的局部变量地址,同时压栈设置栈指针\texttt{\$sp}。 20 | \item 若在优化中采用了寄存器传参和图着色寄存器分配,需要取参数。 21 | \item 随后对每个基本块代码生成,基本块入口处需要计算并分配临时变量空间,压栈指针,离开基本块时回收这部分空间。 22 | \item 生成函数出口,将函数刚刚分配的局部变量空间回收,若是main函数,则结束程序,否则跳转到返回地址。 23 | \end{enumerate} 24 | 25 | \section{设计细节} 26 | 27 | \subsection{寄存器分配} 28 | 29 | 采用一个单独的类\texttt{RegMap}来维护寄存器的分配。\texttt{RegMap}定义如下 30 | \begin{minted}{java} 31 | public class RegMap { 32 | private static final Map BUSY_REG_TO_VAR = new HashMap<>();//寄存器到变量的映射 33 | private static final Map VAR_TO_BUST_REG = new HashMap<>();//变量到寄存器的映射 34 | 35 | private static final Collection availableReg = Collections.unmodifiableList(Arrays.asList( 36 | 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 37 | )); 38 | private static final Set freeRegList = new HashSet<>(availableReg);//目前空闲的寄存器 39 | private static final Set lruList = new LinkedHashSet<>();//LRU队列 40 | private static final Map REG_DIRTY = new HashMap<>(); 41 | //Dirty位,寄存器中的值是否被修改过 42 | 43 | /** 44 | * 分配寄存器,若已经分配过,则返回之前分配的,并更新LRU。 45 | * 若未分配,则分配一个,若需要分配同时加载初值,则needLoad置位。 46 | * 副作用:会在mipsObject中新增代码 47 | */ 48 | public static int allocReg(TableEntry tableEntry, MipsObject mipsObject, boolean needLoad) { 49 | } 50 | //... 51 | } 52 | //... 53 | \end{minted} 54 | 55 | 若没有空闲的寄存器,采用最近最少使用的寄存器置换方法,将最近最少使用的寄存器释放,分配给待分配变量。 56 | 若该寄存器的值的\texttt{Dirty}为\texttt{true},则需要写回对应内存。 57 | 58 | \subsection{运行时存储管理} 59 | 运行栈的结构设计如图\ref{fig:stack}。 60 | \begin{figure}[htbp] 61 | \centering 62 | \includegraphics[width=0.5\linewidth]{img/stack.png} 63 | \caption{运行栈结构设计} 64 | \label{fig:stack} 65 | \end{figure} 66 | 67 | 68 | 通过\texttt{\$gp}访问全局变量,通过\texttt{\$fp}访问局部变量和参数,通过\texttt{\$sp}访问临时变量。 69 | 70 | \subsection{函数调用的现场切换与恢复} 71 | 72 | 发生函数调用时,需要在运行栈上保存好函数的返回地址、分配给局部变量的全局寄存器和当前函数的帧指针\texttt{\$fp},并在函数调用后恢复。 73 | 由于函数调用并不会引起基本块的分割,有些临时变量需要在函数调用后维持原本的值,因此在发生函数调用时,还需要扫描基本块的后续指令,判断哪些 74 | 临时变量还需要用到,将这些临时变量保存在内存对应的位置。其余的不被用到的临时变量可以直接清除映射。 75 | 76 | \subsection{数组寻址的计算} 77 | 78 | 从中间代码的\texttt{getelementptr}指令计算访问地址也是一个难点。本编译器中的\texttt{ElementPtr}定义如下 79 | \begin{minted}{java} 80 | public class ElementPtr extends InstructionLinkNode { 81 | private final TableEntry dst; //计算出的地址的保存变量 82 | private final TableEntry baseVar;//基变量 83 | private final List index = new ArrayList<>(); 84 | //地址运算的index 85 | 86 | //... 87 | } 88 | \end{minted} 89 | 90 | 地址的计算公式为 91 | 92 | $Addr_{baseVar} + 4\Sigma_{i = 0} ^ {index.size} (i < baseVar.dim.size ? baseVar.dim[i] : 1) * index[i]$。 93 | 94 | 其中对于\texttt{baseVar}为数组的访问要比\texttt{baseVar}是指针的访问index在最前多出一个0。 95 | 例如 96 | \begin{minted}{java} 97 | int a[4][5], b[5]; 98 | 99 | a[2][3] = 1; 100 | //为访问a[2][3]产生的index序列为 0, 2, 3 101 | //计算出的offset为4*(4*0+5*2+1*3)=4*13 102 | b[3] = 1; 103 | //为访问b[3]产生的index序列为 0, 3 104 | //计算出的offset为4*(5*0+1*3)=4*3 105 | void foo(int a[][5],int b[]){ 106 | a[2][3] = 1; 107 | //为访问a[2][3]产生的index序列为 2, 3 108 | //参数的第一维缺失,dimension中只有5 109 | //计算出的offset为4*(5*2+1*3)=4*13 110 | b[3] = 1; 111 | //为访问b[3]产生的index序列为 3 112 | //参数的第一维缺失,dimension中为空 113 | //计算出的offset为4*(1*3)=4*3 114 | } 115 | \end{minted} 116 | 117 | 这个计算方法对于更高维的数组也是适用的,若要拓展数组维数,此架构并不需要修改。 118 | 119 | \section{编码后的修改} 120 | 本阶段的主要修改是添加了代码优化后带来的修改,由于加入了图着色寄存器分配和寄存器传参,因此多出了取参数和 121 | 注册图着色分配的寄存器这一步骤,其他部分大体上没有改动。 -------------------------------------------------------------------------------- /report/7-end.tex: -------------------------------------------------------------------------------- 1 | \chapter{结语} 2 | 一学期的编译实验终于进入尾声,回想整个过程,比较深刻的感受可以用“细节繁杂”一词来概括。本学期的编译实验,尤其是调试的时候, 3 | 总会给心态带来冲击。 4 | 5 | 由此,在开始编写文法复杂,细节繁多的编译器的各个模块前,一个整体的设计是十分必要的,先设计再编写是避免一开始就落入繁杂细节的好方法, 6 | 大方向上的正确可以有效避免编码过程中的大规模重构,出现的细节问题也只是多,杂,但往往并不致命,只需要稍作修改就可以解决。当然, 7 | 完美无瑕的整体设计也很难做到,随着编写不断推进,理解不断深入,一些新的问题在这时才会暴露出来,因此在最初设计时,要尽量减少不同模块之间的 8 | 耦合度,让修改更加容易。 9 | 10 | 在优化方面,印象比较深刻的感受是付出有时并不能带来回报,或者说只有不断积累量变才可能带来质变。由于优化的效果和测试数据的结构极为相关, 11 | 在一次次实现新优化后的一次次提交中,有时会发现这项新优化效果并没有反应在测试数据上,不免会感觉十分失落。有时完成一项很简单的优化后,反而 12 | 效果出乎意料很好,这有可能是这项优化自身产生的效果,也可能是和之前优化共同作用的结果。因此需要调整面对竞速点的心态,竞速点涉及到的测试点很少, 13 | 并且是刻意构造过的,即使某项优化在这几个竞速点中没有体现作用,在其他的情况中也许就能有所发挥,成功调通,实现一项优化本身就是值得高兴的事了。 14 | 15 | 当然,建议课程组可以增加一些竞速点,刻意构造过的针对某项优化的测试点很难真实反映优化效果,确实会在过程中带来一些挫败感。 -------------------------------------------------------------------------------- /report/img/stack.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /report/main.out: -------------------------------------------------------------------------------- 1 | \BOOKMARK [0][-]{chapter.1}{\376\377\140\073\117\123\147\266\147\204}{}% 1 2 | \BOOKMARK [0][-]{chapter.2}{\376\377\213\315\154\325\122\006\147\220}{}% 2 3 | \BOOKMARK [1][-]{section.2.1}{\376\377\213\276\213\241\151\202\217\360}{chapter.2}% 3 4 | \BOOKMARK [1][-]{section.2.2}{\376\377\177\026\170\001\124\016\166\204\117\356\145\071}{chapter.2}% 4 5 | \BOOKMARK [0][-]{chapter.3}{\376\377\213\355\154\325\122\006\147\220}{}% 5 6 | \BOOKMARK [1][-]{section.3.1}{\376\377\213\276\213\241\151\202\217\360}{chapter.3}% 6 7 | \BOOKMARK [1][-]{section.3.2}{\376\377\213\276\213\241\176\306\202\202}{chapter.3}% 7 8 | \BOOKMARK [2][-]{subsection.3.2.1}{\376\377\145\207\154\325\135\346\220\022\137\122\131\004\164\006}{section.3.2}% 8 9 | \BOOKMARK [2][-]{subsection.3.2.2}{\376\377\215\113\120\074\213\355\123\345\116\016\210\150\217\276\137\017\213\355\123\345\123\072\122\006\225\356\230\230}{section.3.2}% 9 10 | \BOOKMARK [2][-]{subsection.3.2.3}{\376\377\116\072\225\031\213\357\131\004\164\006\230\204\165\131\143\245\123\343}{section.3.2}% 10 11 | \BOOKMARK [1][-]{section.3.3}{\376\377\177\026\170\001\124\016\166\204\117\356\145\071}{chapter.3}% 11 12 | \BOOKMARK [0][-]{chapter.4}{\376\377\213\355\116\111\122\006\147\220\124\214\225\031\213\357\131\004\164\006}{}% 12 13 | \BOOKMARK [1][-]{section.4.1}{\376\377\213\276\213\241\151\202\217\360}{chapter.4}% 13 14 | \BOOKMARK [1][-]{section.4.2}{\376\377\213\276\213\241\176\306\202\202}{chapter.4}% 14 15 | \BOOKMARK [2][-]{subsection.4.2.1}{\376\377\213\355\154\325\225\031\213\357\131\004\164\006}{section.4.2}% 15 16 | \BOOKMARK [2][-]{subsection.4.2.2}{\376\377\213\355\116\111\122\006\147\220\116\016\213\355\116\111\225\031\213\357\131\004\164\006}{section.4.2}% 16 17 | \BOOKMARK [2][-]{subsection.4.2.3}{\376\377\173\046\123\367\210\150\213\276\213\241}{section.4.2}% 17 18 | \BOOKMARK [1][-]{section.4.3}{\376\377\177\026\170\001\124\016\166\204\117\356\145\071}{chapter.4}% 18 19 | \BOOKMARK [0][-]{chapter.5}{\376\377\116\055\225\364\116\343\170\001\165\037\142\020}{}% 19 20 | \BOOKMARK [1][-]{section.5.1}{\376\377\213\276\213\241\151\202\217\360}{chapter.5}% 20 21 | \BOOKMARK [1][-]{section.5.2}{\376\377\213\276\213\241\176\306\202\202}{chapter.5}% 21 22 | \BOOKMARK [2][-]{subsection.5.2.1}{\376\377\123\330\221\317\166\204\133\232\116\111\124\214\122\035\131\313\123\026}{section.5.2}% 22 23 | \BOOKMARK [2][-]{subsection.5.2.2}{\376\377\123\330\221\317\166\204\213\277\225\356\124\214\215\113\120\074}{section.5.2}% 23 24 | \BOOKMARK [2][-]{subsection.5.2.3}{\376\377\210\150\217\276\137\017\213\241\173\227}{section.5.2}% 24 25 | \BOOKMARK [2][-]{subsection.5.2.4}{\376\377\143\247\122\066\155\101\377\010\137\252\163\257\124\214\122\006\145\057\377\011}{section.5.2}% 25 26 | \BOOKMARK [2][-]{subsection.5.2.5}{\376\377\145\160\176\304\166\204\213\277\225\356}{section.5.2}% 26 27 | \BOOKMARK [2][-]{subsection.5.2.6}{\376\377\167\355\215\357\154\102\120\074}{section.5.2}% 27 28 | \BOOKMARK [1][-]{section.5.3}{\376\377\177\026\170\001\124\016\166\204\117\356\145\071}{chapter.5}% 28 29 | \BOOKMARK [0][-]{chapter.6}{\376\377\166\356\150\007\116\343\170\001\165\037\142\020}{}% 29 30 | \BOOKMARK [1][-]{section.6.1}{\376\377\213\276\213\241\151\202\217\360}{chapter.6}% 30 31 | \BOOKMARK [1][-]{section.6.2}{\376\377\213\276\213\241\176\306\202\202}{chapter.6}% 31 32 | \BOOKMARK [2][-]{subsection.6.2.1}{\376\377\133\304\133\130\126\150\122\006\221\115}{section.6.2}% 32 33 | \BOOKMARK [2][-]{subsection.6.2.2}{\376\377\217\320\210\114\145\366\133\130\120\250\173\241\164\006}{section.6.2}% 33 34 | \BOOKMARK [2][-]{subsection.6.2.3}{\376\377\121\375\145\160\214\003\165\050\166\204\163\260\127\072\122\007\143\142\116\016\140\142\131\015}{section.6.2}% 34 35 | \BOOKMARK [2][-]{subsection.6.2.4}{\376\377\145\160\176\304\133\373\127\100\166\204\213\241\173\227}{section.6.2}% 35 36 | \BOOKMARK [1][-]{section.6.3}{\376\377\177\026\170\001\124\016\166\204\117\356\145\071}{chapter.6}% 36 37 | \BOOKMARK [0][-]{chapter.7}{\376\377\116\343\170\001\117\030\123\026}{}% 37 38 | \BOOKMARK [1][-]{section.7.1}{\376\377\213\276\213\241\151\202\217\360}{chapter.7}% 38 39 | \BOOKMARK [1][-]{section.7.2}{\376\377\117\123\174\373\176\323\147\204\145\340\121\163\117\030\123\026}{chapter.7}% 39 40 | \BOOKMARK [2][-]{subsection.7.2.1}{\376\377\155\101\126\376\136\372\172\313}{section.7.2}% 40 41 | \BOOKMARK [2][-]{subsection.7.2.2}{\376\377\124\010\136\166\127\372\147\054\127\127}{section.7.2}% 41 42 | \BOOKMARK [2][-]{subsection.7.2.3}{\376\377\172\245\133\124\117\030\123\026}{section.7.2}% 42 43 | \BOOKMARK [2][-]{subsection.7.2.4}{\376\377\122\060\217\276\133\232\116\111\122\006\147\220}{section.7.2}% 43 44 | \BOOKMARK [2][-]{subsection.7.2.5}{\376\377\136\070\221\317\117\040\144\255}{section.7.2}% 44 45 | \BOOKMARK [2][-]{subsection.7.2.6}{\376\377\131\015\121\231\117\040\144\255}{section.7.2}% 45 46 | \BOOKMARK [2][-]{subsection.7.2.7}{\376\377\127\372\147\054\127\127\121\205\220\350\166\204\153\173\116\343\170\001\122\040\226\144}{section.7.2}% 46 47 | \BOOKMARK [2][-]{subsection.7.2.8}{\376\377\155\073\215\303\123\330\221\317\122\006\147\220}{section.7.2}% 47 48 | \BOOKMARK [2][-]{subsection.7.2.9}{\376\377\215\350\127\372\147\054\127\127\166\204\153\173\116\343\170\001\122\040\226\144}{section.7.2}% 48 49 | \BOOKMARK [2][-]{subsection.7.2.10}{\376\377\137\252\163\257\176\323\147\204\117\030\123\026}{section.7.2}% 49 50 | \BOOKMARK [1][-]{section.7.3}{\376\377\117\123\174\373\176\323\147\204\166\370\121\163\117\030\123\026}{chapter.7}% 50 51 | \BOOKMARK [2][-]{subsection.7.3.1}{\376\377\126\376\167\100\202\162\133\304\133\130\126\150\122\006\221\115}{section.7.3}% 51 52 | \BOOKMARK [2][-]{subsection.7.3.2}{\376\377\116\130\226\144\117\030\123\026}{section.7.3}% 52 53 | \BOOKMARK [2][-]{subsection.7.3.3}{\376\377\143\007\116\344\220\011\142\351\117\030\123\026}{section.7.3}% 53 54 | \BOOKMARK [0][-]{chapter.8}{\376\377\176\323\213\355}{}% 54 55 | -------------------------------------------------------------------------------- /report/main.tex: -------------------------------------------------------------------------------- 1 | % !TEX root = main.tex 2 | 3 | \documentclass[fontset=fandol]{ctexrep} 4 | 5 | \newcommand{\artdate}{2022年12月} 6 | 7 | \usepackage[toc,page]{appendix} 8 | \usepackage{graphicx} 9 | \usepackage{geometry} 10 | \usepackage{lscape} 11 | \usepackage{hyperref} 12 | \usepackage{hyperxmp} 13 | \usepackage{longtable} 14 | \usepackage{booktabs} 15 | \usepackage[bottom]{footmisc} 16 | \usepackage{subcaption} 17 | \usepackage{url} 18 | \usepackage{bytefield} 19 | \usepackage{xcolor} 20 | \usepackage{minted} 21 | \usepackage{threeparttable} 22 | \usepackage{multirow} 23 | \usepackage{float} 24 | \usepackage{amsmath} 25 | \usepackage{pythonhighlight} 26 | \usepackage{mathtools,lmodern} 27 | 28 | \newcommand{\artauthor}{} 29 | \newcommand{\arttitle}{SysY-MIPS-Compiler设计报告} 30 | 31 | \newcommand{\todo}{\textbf{\textcolor{red}{此部分尚需完善。}}} 32 | 33 | \hypersetup{pdfauthor=\artauthor, 34 | pdftitle=\arttitle, 35 | pdfdate=\artdate, 36 | pdfdisplaydoctitle=true, 37 | pdflang=zh-CN, 38 | pdfstartview=FitH, 39 | colorlinks=true, 40 | linkcolor=blue 41 | } 42 | 43 | \geometry{ 44 | a4paper, 45 | left=3.18cm, 46 | right=3.18cm, 47 | top=2.54cm, 48 | bottom=2.54cm 49 | } 50 | 51 | \graphicspath{{figures/}} 52 | 53 | \ctexset{chapter={ 54 | name={第,部分}, 55 | number=\chinese{chapter}, 56 | }, 57 | listfigurename=插图索引, 58 | listtablename=表格索引 59 | } 60 | 61 | \setminted{frame=lines, linenos=true, breaklines=true} 62 | 63 | \begin{document} 64 | 65 | \begin{titlepage} 66 | 67 | \newcommand{\HRule}{\rule{\linewidth}{0.5mm}} 68 | 69 | \vfill 70 | \center 71 | 72 | \textit{\Large 北京航空航天大学}\\[0.5cm] 73 | \texttt{\Large 计算机学院} 74 | 75 | \vspace{3 cm} 76 | \HRule \\[0.4cm] 77 | { \huge \bfseries 编译技术}\\[0.4cm] 78 | { \huge \bfseries SysY-MIPS-Compiler设计报告}\\ 79 | \HRule \\[1cm] 80 | 81 | \vspace{2.5 cm} 82 | 龚悦\\ 83 | 学号:20373091\\ 84 | 班级:200615\\ 85 | 86 | \vspace{1 cm} 87 | {\large \artdate}\\[3cm] 88 | 89 | \vfill 90 | 91 | \end{titlepage} 92 | 93 | \tableofcontents 94 | \input{0-summary} 95 | \input{1-lexer} 96 | \input{2-parser} 97 | \input{3-semanic} 98 | \input{4-midcode} 99 | \input{5-target} 100 | \input{6-optimize} 101 | \input{7-end} 102 | \end{document} 103 | -------------------------------------------------------------------------------- /report/main.toc: -------------------------------------------------------------------------------- 1 | \contentsline {chapter}{\numberline {第一部分\hspace {.3em}}总体架构}{3}{chapter.1}% 2 | \contentsline {chapter}{\numberline {第二部分\hspace {.3em}}词法分析}{5}{chapter.2}% 3 | \contentsline {section}{\numberline {2.1}设计概述}{5}{section.2.1}% 4 | \contentsline {section}{\numberline {2.2}编码后的修改}{5}{section.2.2}% 5 | \contentsline {chapter}{\numberline {第三部分\hspace {.3em}}语法分析}{6}{chapter.3}% 6 | \contentsline {section}{\numberline {3.1}设计概述}{6}{section.3.1}% 7 | \contentsline {section}{\numberline {3.2}设计细节}{6}{section.3.2}% 8 | \contentsline {subsection}{\numberline {3.2.1}文法左递归处理}{6}{subsection.3.2.1}% 9 | \contentsline {subsection}{\numberline {3.2.2}赋值语句与表达式语句区分问题}{7}{subsection.3.2.2}% 10 | \contentsline {subsection}{\numberline {3.2.3}为错误处理预留接口}{7}{subsection.3.2.3}% 11 | \contentsline {section}{\numberline {3.3}编码后的修改}{7}{section.3.3}% 12 | \contentsline {chapter}{\numberline {第四部分\hspace {.3em}}语义分析和错误处理}{8}{chapter.4}% 13 | \contentsline {section}{\numberline {4.1}设计概述}{8}{section.4.1}% 14 | \contentsline {section}{\numberline {4.2}设计细节}{8}{section.4.2}% 15 | \contentsline {subsection}{\numberline {4.2.1}语法错误处理}{8}{subsection.4.2.1}% 16 | \contentsline {subsection}{\numberline {4.2.2}语义分析与语义错误处理}{8}{subsection.4.2.2}% 17 | \contentsline {subsection}{\numberline {4.2.3}符号表设计}{9}{subsection.4.2.3}% 18 | \contentsline {section}{\numberline {4.3}编码后的修改}{10}{section.4.3}% 19 | \contentsline {chapter}{\numberline {第五部分\hspace {.3em}}中间代码生成}{11}{chapter.5}% 20 | \contentsline {section}{\numberline {5.1}设计概述}{11}{section.5.1}% 21 | \contentsline {section}{\numberline {5.2}设计细节}{11}{section.5.2}% 22 | \contentsline {subsection}{\numberline {5.2.1}变量的定义和初始化}{11}{subsection.5.2.1}% 23 | \contentsline {subsection}{\numberline {5.2.2}变量的访问和赋值}{12}{subsection.5.2.2}% 24 | \contentsline {subsection}{\numberline {5.2.3}表达式计算}{12}{subsection.5.2.3}% 25 | \contentsline {subsection}{\numberline {5.2.4}控制流(循环和分支)}{13}{subsection.5.2.4}% 26 | \contentsline {subsubsection}{分支}{13}{subsubsection*.8}% 27 | \contentsline {subsubsection}{循环}{14}{subsubsection*.9}% 28 | \contentsline {subsection}{\numberline {5.2.5}数组的访问}{14}{subsection.5.2.5}% 29 | \contentsline {subsection}{\numberline {5.2.6}短路求值}{14}{subsection.5.2.6}% 30 | \contentsline {subsubsection}{分支的\&\&短路}{14}{subsubsection*.10}% 31 | \contentsline {subsubsection}{分支的||短路}{15}{subsubsection*.11}% 32 | \contentsline {subsubsection}{循环的短路}{15}{subsubsection*.12}% 33 | \contentsline {section}{\numberline {5.3}编码后的修改}{16}{section.5.3}% 34 | \contentsline {chapter}{\numberline {第六部分\hspace {.3em}}目标代码生成}{17}{chapter.6}% 35 | \contentsline {section}{\numberline {6.1}设计概述}{17}{section.6.1}% 36 | \contentsline {section}{\numberline {6.2}设计细节}{18}{section.6.2}% 37 | \contentsline {subsection}{\numberline {6.2.1}寄存器分配}{18}{subsection.6.2.1}% 38 | \contentsline {subsection}{\numberline {6.2.2}运行时存储管理}{18}{subsection.6.2.2}% 39 | \contentsline {subsection}{\numberline {6.2.3}函数调用的现场切换与恢复}{19}{subsection.6.2.3}% 40 | \contentsline {subsection}{\numberline {6.2.4}数组寻址的计算}{19}{subsection.6.2.4}% 41 | \contentsline {section}{\numberline {6.3}编码后的修改}{20}{section.6.3}% 42 | \contentsline {chapter}{\numberline {第七部分\hspace {.3em}}代码优化}{21}{chapter.7}% 43 | \contentsline {section}{\numberline {7.1}设计概述}{21}{section.7.1}% 44 | \contentsline {section}{\numberline {7.2}体系结构无关优化}{21}{section.7.2}% 45 | \contentsline {subsection}{\numberline {7.2.1}流图建立}{21}{subsection.7.2.1}% 46 | \contentsline {subsection}{\numberline {7.2.2}合并基本块}{22}{subsection.7.2.2}% 47 | \contentsline {subsection}{\numberline {7.2.3}窥孔优化}{22}{subsection.7.2.3}% 48 | \contentsline {subsubsection}{单条指令优化}{22}{subsubsection*.15}% 49 | \contentsline {subsubsection}{连续的访存指令优化}{22}{subsubsection*.16}% 50 | \contentsline {subsection}{\numberline {7.2.4}到达定义分析}{22}{subsection.7.2.4}% 51 | \contentsline {subsection}{\numberline {7.2.5}常量传播}{23}{subsection.7.2.5}% 52 | \contentsline {subsection}{\numberline {7.2.6}复写传播}{24}{subsection.7.2.6}% 53 | \contentsline {subsection}{\numberline {7.2.7}基本块内部的死代码删除}{25}{subsection.7.2.7}% 54 | \contentsline {subsubsection}{基本块内部的临时变量死代码}{25}{subsubsection*.17}% 55 | \contentsline {subsubsection}{不可达代码}{25}{subsubsection*.18}% 56 | \contentsline {subsection}{\numberline {7.2.8}活跃变量分析}{25}{subsection.7.2.8}% 57 | \contentsline {subsection}{\numberline {7.2.9}跨基本块的死代码删除}{26}{subsection.7.2.9}% 58 | \contentsline {subsection}{\numberline {7.2.10}循环结构优化}{26}{subsection.7.2.10}% 59 | \contentsline {section}{\numberline {7.3}体系结构相关优化}{27}{section.7.3}% 60 | \contentsline {subsection}{\numberline {7.3.1}图着色寄存器分配}{27}{subsection.7.3.1}% 61 | \contentsline {subsubsection}{冲突图建立}{27}{subsubsection*.19}% 62 | \contentsline {subsubsection}{舍弃变量}{27}{subsubsection*.20}% 63 | \contentsline {subsection}{\numberline {7.3.2}乘除优化}{27}{subsection.7.3.2}% 64 | \contentsline {subsubsection}{乘法优化}{27}{subsubsection*.21}% 65 | \contentsline {subsubsection}{除法优化}{28}{subsubsection*.22}% 66 | \contentsline {subsubsection}{取模优化}{29}{subsubsection*.26}% 67 | \contentsline {subsection}{\numberline {7.3.3}指令选择优化}{29}{subsection.7.3.3}% 68 | \contentsline {chapter}{\numberline {第八部分\hspace {.3em}}结语}{30}{chapter.8}% 69 | -------------------------------------------------------------------------------- /report/结语.md: -------------------------------------------------------------------------------- 1 | # 结语 2 | 3 | ###### 20373091 龚悦 4 | 5 | 一学期的编译实验终于进入尾声,回想整个过程,比较深刻的感受可以用“细节繁杂”一词来概括。本学期的编译实验,尤其是调试的时候,总会给心态带来冲击。 6 | 7 | 由此,在开始编写文法复杂,细节繁多的编译器的各个模块前,一个整体的设计是十分必要的,先设计再编写是避免一开始就落入繁杂细节的好方法,大方向上的正确可以有效避免编码过程中的大规模重构,出现的细节问题也只是多,杂,但往往并不致命,只需要稍作修改就可以解决。当然,完美无瑕的整体设计也很难做到,随着编写不断推进,理解不断深入,一些新的问题在这时才会暴露出来,因此在最初设计时,要尽量减少不同模块之间的耦合度,让修改更加容易。 8 | 9 | 在优化方面,印象比较深刻的感受是付出有时并不能带来回报,或者说只有不断积累量变才可能带来质变。由于优化的效果和测试数据的结构极为相关,在一次次实现新优化后的一次次提交中,有时会发现这项新优化效果并没有反应在测试数据上,不免会感觉十分失落。有时完成一项很简单的优化后,反而效果出乎意料很好,这有可能是这项优化自身产生的效果,也可能是和之前优化共同作用的结果。因此需要调整面对竞速点的心态,竞速点涉及到的测试点很少,并且是刻意构造过的,即使某项优化在这几个竞速点中没有体现作用,在其他的情况中也许就能有所发挥,成功调通,实现一项优化本身就是值得高兴的事了。 10 | 11 | 当然,建议课程组可以增加一些竞速点,刻意构造过的针对某项优化的测试点很难真实反映优化效果,确实会在过程中带来一些挫败感。 -------------------------------------------------------------------------------- /report/编译实验设计报告.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arthuring/SysY-MIPS-Compiler/efa57a2f0b13c1b13c9076fd232090019b2d270e/report/编译实验设计报告.pdf -------------------------------------------------------------------------------- /src/back/MipsObject.java: -------------------------------------------------------------------------------- 1 | package back; 2 | 3 | import back.hardware.Memory; 4 | import back.hardware.RF; 5 | import back.instr.MipsInstr; 6 | import mid.StringCounter; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.StringJoiner; 12 | 13 | public class MipsObject { 14 | private final MipsInstr entry = new MipsInstr(); 15 | private final MipsInstr exit = new MipsInstr(); 16 | public static final int STR_START_ADDR = 0x10000000; 17 | public static final int DATA_START_ADDR = RF.GP_INIT; 18 | private final Memory initMem = new Memory(); 19 | private List labelToSet = new ArrayList<>(); 20 | private final List irDescription = new ArrayList<>(); 21 | private String comment = null; 22 | 23 | 24 | public MipsObject() { 25 | entry.setNext(exit); 26 | exit.setPrev(entry); 27 | } 28 | 29 | public MipsInstr getFirstInstr() { 30 | return (MipsInstr) entry.next(); 31 | } 32 | 33 | public MipsInstr getLastInstr() { 34 | return (MipsInstr) exit.prev(); 35 | } 36 | 37 | public void addAfter(MipsInstr after) { 38 | if (!labelToSet.isEmpty()) { 39 | after.setLabel(labelToSet); 40 | labelToSet.clear(); 41 | } 42 | if (!irDescription.isEmpty()) { 43 | after.setIrDescription(irDescription); 44 | irDescription.clear(); 45 | } 46 | if (comment != null) { 47 | after.setComment(comment); 48 | comment = null; 49 | } 50 | MipsInstr lastInst = getLastInstr(); 51 | lastInst.setNext(after); 52 | after.setPrev(lastInst); 53 | MipsInstr ptr = after; 54 | while (ptr.hasNext()) { 55 | ptr = (MipsInstr) ptr.next(); 56 | } 57 | exit.setPrev(ptr); 58 | ptr.setNext(exit); 59 | } 60 | 61 | public Memory initMem() { 62 | return initMem; 63 | } 64 | 65 | public void setLabelToSet(String labelToSet) { 66 | this.labelToSet.add(labelToSet); 67 | } 68 | 69 | public void addIrDescription(String irDescription) { 70 | if (irDescription != null) { 71 | this.irDescription.add(irDescription.replace("\t", "")); 72 | } 73 | } 74 | 75 | public void setComment(String comment) { 76 | this.comment = comment.replace("\t", ""); 77 | } 78 | 79 | public String toMips() { 80 | StringJoiner sj = new StringJoiner("\n"); 81 | sj.add(".data 0x" + Integer.toHexString(STR_START_ADDR)); 82 | for (Map.Entry stringStringEntry : StringCounter.getStr2Label().entrySet()) { 83 | sj.add(stringStringEntry.getValue() + ":" + " .asciiz " + 84 | "\"" + stringStringEntry.getKey() + "\""); 85 | } 86 | sj.add(".data 0x" + Integer.toHexString(DATA_START_ADDR)); 87 | for (int i = 0; i < initMem.getGlobalOffset(); i += 4) { 88 | sj.add(".word " + initMem.loadWord(i)); 89 | } 90 | 91 | sj.add(".text"); 92 | MipsInstr ptr = getFirstInstr(); 93 | while (ptr.hasNext()) { 94 | sj.add(ptr.toMips()); 95 | ptr = (MipsInstr) ptr.next(); 96 | } 97 | if (!this.labelToSet.isEmpty()) { 98 | for (String label : labelToSet) { 99 | sj.add(label + ":"); 100 | } 101 | } 102 | return sj.toString(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/back/hardware/Memory.java: -------------------------------------------------------------------------------- 1 | package back.hardware; 2 | 3 | import front.TableEntry; 4 | import front.nodes.NumberNode; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class Memory { 10 | private final Map globalVarMap = new HashMap<>(); //全局变量 - 虚地址 11 | private int globalOffset = 0; 12 | private final Map memoryMap = new HashMap<>(); //虚地址 - 值 13 | 14 | public Memory() { 15 | 16 | } 17 | 18 | public static int roundUp(int value, int round) { 19 | return value % round == 0 ? value : round * (value / round + 1); 20 | } 21 | 22 | public static int roundDown(int value, int round) { 23 | return value % round == 0 ? value : round * (value / round); 24 | } 25 | 26 | public int allocGlobalVar(TableEntry tableEntry) { 27 | if (globalVarMap.containsKey(tableEntry)) { 28 | return globalVarMap.get(tableEntry); 29 | } 30 | int offset = roundUp(globalOffset, 4); 31 | globalOffset = roundUp(globalOffset, 4); 32 | tableEntry.setAddress(offset); 33 | globalVarMap.put(tableEntry, RF.GP_INIT + offset); 34 | 35 | if (tableEntry.refType == TableEntry.RefType.ITEM) { 36 | int value = tableEntry.initValue == null ? 0 : ((NumberNode) tableEntry.initValue).number(); 37 | memoryMap.put(RF.GP_INIT + globalOffset, value); 38 | globalOffset += tableEntry.valueType.sizeof(); 39 | } else { 40 | //TODO : 数组 41 | for (int i = 0; i < tableEntry.sizeof(); i += 4) { 42 | int value = tableEntry.initValueList == null ? 0 : 43 | ((NumberNode) tableEntry.initValueList.get(i / 4)).number(); 44 | memoryMap.put(RF.GP_INIT + globalOffset, value); 45 | globalOffset += 4; 46 | } 47 | } 48 | 49 | return offset; 50 | } 51 | 52 | public int loadWord(int offset) { 53 | return memoryMap.getOrDefault(RF.GP_INIT + offset, 0); 54 | } 55 | 56 | public int getGlobalOffset() { 57 | return globalOffset; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/back/hardware/RF.java: -------------------------------------------------------------------------------- 1 | package back.hardware; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | public class RF { 10 | private static final int TEXT_BASE = 0x00400000; 11 | public static final int GP_INIT = 0x10008000; 12 | public static final int SP_INIT = 0x7fffeffc; 13 | public static final Map ID_TO_NAME = new HashMap() { 14 | { 15 | put(0, "zero"); 16 | put(1, "at"); 17 | put(2, "v0"); 18 | put(3, "v1"); 19 | put(4, "a0"); 20 | put(5, "a1"); 21 | put(6, "a2"); 22 | put(7, "a3"); 23 | put(8, "t0"); 24 | put(9, "t1"); 25 | put(10, "t2"); 26 | put(11, "t3"); 27 | put(12, "t4"); 28 | put(13, "t5"); 29 | put(14, "t6"); 30 | put(15, "t7"); 31 | put(16, "s0"); 32 | put(17, "s1"); 33 | put(18, "s2"); 34 | put(19, "s3"); 35 | put(20, "s4"); 36 | put(21, "s5"); 37 | put(22, "s6"); 38 | put(23, "s7"); 39 | put(24, "t8"); 40 | put(25, "t9"); 41 | put(26, "k0"); 42 | put(27, "k1"); 43 | put(28, "gp"); 44 | put(29, "sp"); 45 | put(30, "fp"); 46 | put(31, "ra"); 47 | } 48 | }; 49 | 50 | private final List grf = Collections.unmodifiableList( 51 | Arrays.asList( 52 | new Reg("zero"), new Reg("at"), new Reg("v0"), new Reg("v1"), 53 | new Reg("a0"), new Reg("a1"), new Reg("a2"), new Reg("a3"), 54 | new Reg("t0"), new Reg("t1"), new Reg("t2"), new Reg("t3"), 55 | new Reg("t4"), new Reg("t5"), new Reg("t6"), new Reg("t7"), 56 | new Reg("s0"), new Reg("s1"), new Reg("s2"), new Reg("s3"), 57 | new Reg("s4"), new Reg("s5"), new Reg("s6"), new Reg("s7"), 58 | new Reg("t8"), new Reg("t9"), new Reg("k0"), new Reg("k1"), 59 | new Reg("gp", GP_INIT), new Reg("sp", SP_INIT), new Reg("fp"), new Reg("ra") 60 | ) 61 | ); 62 | 63 | private final Reg HI = new Reg("hi"); 64 | private final Reg LO = new Reg("lo"); 65 | private final Reg PC = new Reg("pc", TEXT_BASE); 66 | 67 | public static class GPR { 68 | public static final int ZERO = 0; 69 | public static final int AT = 1; 70 | public static final int V0 = 2; 71 | public static final int V1 = 3; 72 | public static final int A0 = 4; 73 | public static final int A1 = 5; 74 | public static final int A2 = 6; 75 | public static final int A3 = 7; 76 | public static final int T0 = 8; 77 | public static final int T1 = 9; 78 | public static final int T2 = 10; 79 | public static final int T3 = 11; 80 | public static final int T4 = 12; 81 | public static final int T5 = 13; 82 | public static final int T6 = 14; 83 | public static final int T7 = 15; 84 | public static final int S0 = 16; 85 | public static final int S1 = 17; 86 | public static final int S2 = 18; 87 | public static final int S3 = 19; 88 | public static final int S4 = 20; 89 | public static final int S5 = 21; 90 | public static final int S6 = 22; 91 | public static final int S7 = 23; 92 | public static final int T8 = 24; 93 | public static final int T9 = 25; 94 | public static final int K0 = 26; 95 | public static final int K1 = 27; 96 | public static final int GP = 28; 97 | public static final int SP = 29; 98 | public static final int FP = 30; 99 | public static final int RA = 31; 100 | } 101 | 102 | public int read(int id) { 103 | return grf.get(id).read(); 104 | } 105 | 106 | public void write(int id, int value) { 107 | grf.get(id).write(value); 108 | } 109 | 110 | public int readHi() { 111 | return HI.read(); 112 | } 113 | 114 | public int readLo() { 115 | return LO.read(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/back/hardware/Reg.java: -------------------------------------------------------------------------------- 1 | package back.hardware; 2 | 3 | public class Reg { 4 | private int value = 0; 5 | private final String name; 6 | 7 | public Reg(String name) { 8 | this.name = name; 9 | } 10 | 11 | public Reg(String name, int value) { 12 | this.name = name; 13 | this.value = value; 14 | } 15 | 16 | public int read() { 17 | return value; 18 | } 19 | 20 | public void write(int value) { 21 | if (!this.name.equals("zero")) { 22 | this.value = value; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/back/instr/Addiu.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Addiu extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int imm; 11 | 12 | public Addiu(int rd, int rs, int imm) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.imm = imm; 16 | } 17 | 18 | public Addiu(String label, int rd, int rs, int imm) { 19 | super.setLabel(label); 20 | this.rd = rd; 21 | this.rs = rs; 22 | this.imm = imm; 23 | } 24 | 25 | public int getImm() { 26 | return imm; 27 | } 28 | 29 | public int getRd() { 30 | return rd; 31 | } 32 | 33 | public int getRs() { 34 | return rs; 35 | } 36 | 37 | @Override 38 | public String toMips() { 39 | StringJoiner sj = new StringJoiner("\n"); 40 | sj.add(super.toMips()); 41 | String sb = "addiu " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 42 | "$" + RF.ID_TO_NAME.get(rs) + ", " + imm; 43 | StringBuilder stringBuilder = new StringBuilder(sb); 44 | if (!super.getComment().equals("")) { 45 | stringBuilder.append("\t# ").append(super.getComment()); 46 | } 47 | sj.add(stringBuilder.toString()); 48 | return sj.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/back/instr/Addu.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Addu extends MipsInstr { 8 | private final int rd; 9 | private final int rt; 10 | private final int rs; 11 | 12 | public Addu(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRd() { 23 | return rd; 24 | } 25 | 26 | public int getRt() { 27 | return rt; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "addu " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Beq.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Beq extends MipsInstr { 8 | private final int rs; 9 | private final int rt; 10 | private final String target; 11 | 12 | public Beq(int rs, int rt, String label) { 13 | this.rs = rs; 14 | this.rt = rt; 15 | this.target = label; 16 | } 17 | 18 | public String getTarget() { 19 | return target; 20 | } 21 | 22 | public int getRs() { 23 | return rs; 24 | } 25 | 26 | public int getRt() { 27 | return rt; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "beq " + "$" + RF.ID_TO_NAME.get(rs) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rt) + ", " + target; 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Bne.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Bne extends MipsInstr { 8 | private final int rs; 9 | private final int rt; 10 | private final String target; 11 | 12 | public Bne(int rs, int rt, String label) { 13 | this.rs = rs; 14 | this.rt = rt; 15 | this.target = label; 16 | } 17 | 18 | public int getRt() { 19 | return rt; 20 | } 21 | 22 | public int getRs() { 23 | return rs; 24 | } 25 | 26 | public String getTarget() { 27 | return target; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "bne " + "$" + RF.ID_TO_NAME.get(rs) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rt) + ", " + target; 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Div.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Div extends MipsInstr { 8 | private final int rs; 9 | private final int rt; 10 | 11 | public Div(int rs, int rt) { 12 | this.rs = rs; 13 | this.rt = rt; 14 | } 15 | 16 | public int getRt() { 17 | return rt; 18 | } 19 | 20 | public int getRs() { 21 | return rs; 22 | } 23 | 24 | public String toMips() { 25 | StringJoiner sj = new StringJoiner("\n"); 26 | sj.add(super.toMips()); 27 | String sb = "div " + "$" + RF.ID_TO_NAME.get(rs) + ", " + 28 | "$" + RF.ID_TO_NAME.get(rt); 29 | StringBuilder stringBuilder = new StringBuilder(sb); 30 | if (!super.getComment().equals("")) { 31 | stringBuilder.append("\t# ").append(super.getComment()); 32 | } 33 | sj.add(stringBuilder.toString()); 34 | return sj.toString(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/back/instr/J.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import java.util.StringJoiner; 4 | 5 | public class J extends MipsInstr { 6 | private final String target; 7 | 8 | public J(String target) { 9 | this.target = target; 10 | } 11 | 12 | public String getTarget() { 13 | return target; 14 | } 15 | 16 | public String toMips() { 17 | StringJoiner sj = new StringJoiner("\n"); 18 | sj.add(super.toMips()); 19 | String sb = "j " + target; 20 | StringBuilder stringBuilder = new StringBuilder(sb); 21 | if (!super.getComment().equals("")) { 22 | stringBuilder.append("\t# ").append(super.getComment()); 23 | } 24 | sj.add(stringBuilder.toString()); 25 | return sj.toString(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/back/instr/Jal.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import java.util.StringJoiner; 4 | 5 | public class Jal extends MipsInstr { 6 | private final String tar; 7 | 8 | public Jal(String tar) { 9 | this.tar = tar; 10 | } 11 | 12 | public String toMips() { 13 | StringJoiner sj = new StringJoiner("\n"); 14 | sj.add(super.toMips()); 15 | String sb = "jal " + tar; 16 | StringBuilder stringBuilder = new StringBuilder(sb); 17 | if (!super.getComment().equals("")) { 18 | stringBuilder.append("\t# ").append(super.getComment()); 19 | } 20 | sj.add(stringBuilder.toString()); 21 | return sj.toString(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/back/instr/Jr.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Jr extends MipsInstr { 8 | private final int rd; 9 | 10 | public Jr(int rd) { 11 | this.rd = rd; 12 | } 13 | 14 | public int getRd() { 15 | return rd; 16 | } 17 | 18 | public String toMips() { 19 | StringJoiner sj = new StringJoiner("\n"); 20 | sj.add(super.toMips()); 21 | String sb = "jr " + "$" + RF.ID_TO_NAME.get(rd); 22 | StringBuilder stringBuilder = new StringBuilder(sb); 23 | if (!super.getComment().equals("")) { 24 | stringBuilder.append("\t# ").append(super.getComment()); 25 | } 26 | sj.add(stringBuilder.toString()); 27 | return sj.toString(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/back/instr/La.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class La extends MipsInstr { 8 | private final int dst; 9 | private final String addressLabel; 10 | 11 | public La(int dst, String label) { 12 | this.dst = dst; 13 | this.addressLabel = label; 14 | } 15 | 16 | public String getAddressLabel() { 17 | return addressLabel; 18 | } 19 | 20 | public int getDst() { 21 | return dst; 22 | } 23 | 24 | public String toMips() { 25 | StringJoiner sj = new StringJoiner("\n"); 26 | sj.add(super.toMips()); 27 | String sb = "la " + "$" + RF.ID_TO_NAME.get(dst) + ", " + addressLabel; 28 | StringBuilder stringBuilder = new StringBuilder(sb); 29 | if (!super.getComment().equals("")) { 30 | stringBuilder.append("\t# ").append(super.getComment()); 31 | } 32 | sj.add(stringBuilder.toString()); 33 | return sj.toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/back/instr/Lb.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | public class Lb { 4 | } 5 | -------------------------------------------------------------------------------- /src/back/instr/Lh.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | public class Lh { 4 | } 5 | -------------------------------------------------------------------------------- /src/back/instr/Li.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Li extends MipsInstr { 8 | private final int rd; 9 | private final int imm; 10 | 11 | public Li(int rd, int imm) { 12 | this.rd = rd; 13 | this.imm = imm; 14 | } 15 | 16 | public int getRd() { 17 | return rd; 18 | } 19 | 20 | public int getImm() { 21 | return imm; 22 | } 23 | 24 | public String toMips() { 25 | StringJoiner sj = new StringJoiner("\n"); 26 | sj.add(super.toMips()); 27 | String sb = "li " + "$" + RF.ID_TO_NAME.get(rd) + ", " + imm; 28 | StringBuilder stringBuilder = new StringBuilder(sb); 29 | if (!super.getComment().equals("")) { 30 | stringBuilder.append("\t# ").append(super.getComment()); 31 | } 32 | sj.add(stringBuilder.toString()); 33 | return sj.toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/back/instr/Lw.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Lw extends MipsInstr { 8 | private final int rt; 9 | private final int base; 10 | private final int offset; 11 | 12 | public Lw(int rt, int offset, int base) { 13 | this.rt = rt; 14 | this.offset = offset; 15 | this.base = base; 16 | } 17 | 18 | public Lw(int rt, int offset, int base, String label) { 19 | super.setLabel(label); 20 | this.rt = rt; 21 | this.offset = offset; 22 | this.base = base; 23 | } 24 | 25 | public int getRt() { 26 | return rt; 27 | } 28 | 29 | public int getBase() { 30 | return base; 31 | } 32 | 33 | public int getOffset() { 34 | return offset; 35 | } 36 | 37 | public String toMips() { 38 | StringJoiner sj = new StringJoiner("\n"); 39 | sj.add(super.toMips()); 40 | String sb = "lw " + "$" + RF.ID_TO_NAME.get(rt) + ", " + 41 | offset + "(" + "$" + RF.ID_TO_NAME.get(base) + ")"; 42 | StringBuilder stringBuilder = new StringBuilder(sb); 43 | if (!super.getComment().equals("")) { 44 | stringBuilder.append("\t# ").append(super.getComment()); 45 | } 46 | sj.add(stringBuilder.toString()); 47 | return sj.toString(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/back/instr/Mfhi.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Mfhi extends MipsInstr { 8 | private final int rd; 9 | 10 | public Mfhi(int rd) { 11 | this.rd = rd; 12 | } 13 | 14 | public int getRd() { 15 | return rd; 16 | } 17 | 18 | public String toMips() { 19 | StringJoiner sj = new StringJoiner("\n"); 20 | sj.add(super.toMips()); 21 | String sb = "mfhi " + "$" + RF.ID_TO_NAME.get(rd); 22 | StringBuilder stringBuilder = new StringBuilder(sb); 23 | if (!super.getComment().equals("")) { 24 | stringBuilder.append("\t# ").append(super.getComment()); 25 | } 26 | sj.add(stringBuilder.toString()); 27 | return sj.toString(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/back/instr/Mflo.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Mflo extends MipsInstr { 8 | private final int rd; 9 | 10 | public Mflo(int rd) { 11 | this.rd = rd; 12 | } 13 | 14 | public int getRd() { 15 | return rd; 16 | } 17 | 18 | public String toMips() { 19 | StringJoiner sj = new StringJoiner("\n"); 20 | sj.add(super.toMips()); 21 | String sb = "mflo " + "$" + RF.ID_TO_NAME.get(rd); 22 | StringBuilder stringBuilder = new StringBuilder(sb); 23 | if (!super.getComment().equals("")) { 24 | stringBuilder.append("\t# ").append(super.getComment()); 25 | } 26 | sj.add(stringBuilder.toString()); 27 | return sj.toString(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/back/instr/MipsInstr.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import mid.ircode.InstructionLinkNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.StringJoiner; 8 | 9 | public class MipsInstr extends InstructionLinkNode { 10 | private List label = new ArrayList<>(); 11 | private final List irDescriptions = new ArrayList<>(); 12 | private String comment = ""; 13 | 14 | public String toMips() { 15 | StringJoiner sj = new StringJoiner("\n"); 16 | if (!label.isEmpty()) { 17 | for (String labelItem : label) { 18 | sj.add(labelItem + ":"); 19 | } 20 | } 21 | // for (String description : irDescriptions) { 22 | // String[] strings = description.split("\n"); 23 | // for (String str : strings) { 24 | // sj.add("# " + str); 25 | // } 26 | // } 27 | return sj.toString(); 28 | } 29 | 30 | public List getLabel() { 31 | return label; 32 | } 33 | 34 | public void setLabel(List label) { 35 | this.label.addAll(label); 36 | } 37 | 38 | public void setLabel(String label) { 39 | this.label.add(label); 40 | } 41 | 42 | public void setIrDescription(List irDescriptions) { 43 | this.irDescriptions.addAll(irDescriptions); 44 | } 45 | 46 | public List getIrDescriptions() { 47 | return irDescriptions; 48 | } 49 | 50 | public void setComment(String comment) { 51 | this.comment = comment; 52 | } 53 | 54 | public String getComment() { 55 | return comment; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/back/instr/Move.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Move extends MipsInstr { 8 | private final int dst; 9 | private final int src; 10 | 11 | public Move(int dst, int src) { 12 | this.dst = dst; 13 | this.src = src; 14 | } 15 | 16 | public int getDst() { 17 | return dst; 18 | } 19 | 20 | public int getSrc() { 21 | return src; 22 | } 23 | 24 | public String toMips() { 25 | StringJoiner sj = new StringJoiner("\n"); 26 | sj.add(super.toMips()); 27 | String sb = "move " + "$" + RF.ID_TO_NAME.get(dst) + ", " + 28 | "$" + RF.ID_TO_NAME.get(src); 29 | StringBuilder stringBuilder = new StringBuilder(sb); 30 | if (!super.getComment().equals("")) { 31 | stringBuilder.append("\t# ").append(super.getComment()); 32 | } 33 | sj.add(stringBuilder.toString()); 34 | return sj.toString(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/back/instr/Mul.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Mul extends MipsInstr { 8 | private final int rd; 9 | private final int rt; 10 | private final int rs; 11 | 12 | public Mul(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRd() { 23 | return rd; 24 | } 25 | 26 | public int getRt() { 27 | return rt; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "mul " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Mult.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Mult extends MipsInstr { 8 | private final int rs; 9 | private final int rt; 10 | 11 | public Mult(int rs, int rt) { 12 | this.rs = rs; 13 | this.rt = rt; 14 | } 15 | 16 | public int getRt() { 17 | return rt; 18 | } 19 | 20 | public int getRs() { 21 | return rs; 22 | } 23 | 24 | public String toMips() { 25 | StringJoiner sj = new StringJoiner("\n"); 26 | sj.add(super.toMips()); 27 | String sb = "mult " + "$" + RF.ID_TO_NAME.get(rs) + ", " + 28 | "$" + RF.ID_TO_NAME.get(rt); 29 | StringBuilder stringBuilder = new StringBuilder(sb); 30 | if (!super.getComment().equals("")) { 31 | stringBuilder.append("\t# ").append(super.getComment()); 32 | } 33 | sj.add(stringBuilder.toString()); 34 | return sj.toString(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/back/instr/Nop.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import java.util.StringJoiner; 4 | 5 | public class Nop extends MipsInstr { 6 | public String toMips() { 7 | StringJoiner sj = new StringJoiner("\n"); 8 | sj.add(super.toMips()); 9 | String sb = "nop"; 10 | StringBuilder stringBuilder = new StringBuilder(sb); 11 | if (!super.getComment().equals("")) { 12 | stringBuilder.append("\t# ").append(super.getComment()); 13 | } 14 | sj.add(stringBuilder.toString()); 15 | return sj.toString(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/back/instr/Sb.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | public class Sb { 4 | } 5 | -------------------------------------------------------------------------------- /src/back/instr/Seq.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Seq extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int rt; 11 | 12 | public Seq(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRt() { 23 | return rt; 24 | } 25 | 26 | public int getRd() { 27 | return rd; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "seq " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Sge.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Sge extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int rt; 11 | 12 | public Sge(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRt() { 23 | return rt; 24 | } 25 | 26 | public int getRd() { 27 | return rd; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "sge " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/back/instr/Sgt.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Sgt extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int rt; 11 | 12 | public Sgt(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRt() { 23 | return rt; 24 | } 25 | 26 | public int getRd() { 27 | return rd; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "sgt " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Sh.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | public class Sh { 4 | } 5 | -------------------------------------------------------------------------------- /src/back/instr/Sle.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Sle extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int rt; 11 | 12 | public Sle(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRt() { 23 | return rt; 24 | } 25 | 26 | public int getRd() { 27 | return rd; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "sle " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Sll.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Sll extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int imm; 11 | 12 | public Sll(int rd, int rs, int imm) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.imm = imm; 16 | } 17 | 18 | public Sll(String label, int rd, int rs, int imm) { 19 | super.setLabel(label); 20 | this.rd = rd; 21 | this.rs = rs; 22 | this.imm = imm; 23 | } 24 | 25 | public int getImm() { 26 | return imm; 27 | } 28 | 29 | public int getRd() { 30 | return rd; 31 | } 32 | 33 | public int getRs() { 34 | return rs; 35 | } 36 | 37 | @Override 38 | public String toMips() { 39 | StringJoiner sj = new StringJoiner("\n"); 40 | sj.add(super.toMips()); 41 | String sb = "sll " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 42 | "$" + RF.ID_TO_NAME.get(rs) + ", " + imm; 43 | StringBuilder stringBuilder = new StringBuilder(sb); 44 | if (!super.getComment().equals("")) { 45 | stringBuilder.append("\t# ").append(super.getComment()); 46 | } 47 | sj.add(stringBuilder.toString()); 48 | return sj.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/back/instr/Slt.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Slt extends MipsInstr{ 8 | private final int rd; 9 | private final int rs; 10 | private final int rt; 11 | 12 | public Slt(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRt() { 23 | return rt; 24 | } 25 | 26 | public int getRd() { 27 | return rd; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "slt " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Slti.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Slti extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int imm; 11 | 12 | public Slti(int rd, int rs, int imm) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.imm = imm; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRt() { 23 | return imm; 24 | } 25 | 26 | public int getRd() { 27 | return rd; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "slti " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + imm; 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Sltu.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Sltu extends MipsInstr { 8 | private final int rd; 9 | private final int rt; 10 | private final int rs; 11 | 12 | public Sltu(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRd() { 23 | return rd; 24 | } 25 | 26 | public int getRt() { 27 | return rt; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "sltu " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Sne.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Sne extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int rt; 11 | 12 | public Sne(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRt() { 23 | return rt; 24 | } 25 | 26 | public int getRd() { 27 | return rd; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "sne " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Sra.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Sra extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int imm; 11 | 12 | public Sra(int rd, int rs, int imm) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.imm = imm; 16 | } 17 | 18 | public Sra(String label, int rd, int rs, int imm) { 19 | super.setLabel(label); 20 | this.rd = rd; 21 | this.rs = rs; 22 | this.imm = imm; 23 | } 24 | 25 | public int getImm() { 26 | return imm; 27 | } 28 | 29 | public int getRd() { 30 | return rd; 31 | } 32 | 33 | public int getRs() { 34 | return rs; 35 | } 36 | 37 | @Override 38 | public String toMips() { 39 | StringJoiner sj = new StringJoiner("\n"); 40 | sj.add(super.toMips()); 41 | String sb = "sra " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 42 | "$" + RF.ID_TO_NAME.get(rs) + ", " + imm; 43 | StringBuilder stringBuilder = new StringBuilder(sb); 44 | if (!super.getComment().equals("")) { 45 | stringBuilder.append("\t# ").append(super.getComment()); 46 | } 47 | sj.add(stringBuilder.toString()); 48 | return sj.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/back/instr/Srl.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Srl extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int imm; 11 | 12 | public Srl(int rd, int rs, int imm) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.imm = imm; 16 | } 17 | 18 | public Srl(String label, int rd, int rs, int imm) { 19 | super.setLabel(label); 20 | this.rd = rd; 21 | this.rs = rs; 22 | this.imm = imm; 23 | } 24 | 25 | public int getImm() { 26 | return imm; 27 | } 28 | 29 | public int getRd() { 30 | return rd; 31 | } 32 | 33 | public int getRs() { 34 | return rs; 35 | } 36 | 37 | @Override 38 | public String toMips() { 39 | StringJoiner sj = new StringJoiner("\n"); 40 | sj.add(super.toMips()); 41 | String sb = "srl " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 42 | "$" + RF.ID_TO_NAME.get(rs) + ", " + imm; 43 | StringBuilder stringBuilder = new StringBuilder(sb); 44 | if (!super.getComment().equals("")) { 45 | stringBuilder.append("\t# ").append(super.getComment()); 46 | } 47 | sj.add(stringBuilder.toString()); 48 | return sj.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/back/instr/Subiu.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Subiu extends MipsInstr{ 8 | private final int rd; 9 | private final int rs; 10 | private final int imm; 11 | 12 | public Subiu(int rd, int rs, int imm) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.imm = imm; 16 | } 17 | 18 | public Subiu(String label, int rd, int rs, int imm) { 19 | super.setLabel(label); 20 | this.rd = rd; 21 | this.rs = rs; 22 | this.imm = imm; 23 | } 24 | 25 | public int getImm() { 26 | return imm; 27 | } 28 | 29 | public int getRd() { 30 | return rd; 31 | } 32 | 33 | public int getRs() { 34 | return rs; 35 | } 36 | 37 | @Override 38 | public String toMips() { 39 | StringJoiner sj = new StringJoiner("\n"); 40 | sj.add(super.toMips()); 41 | String sb = "subiu " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 42 | "$" + RF.ID_TO_NAME.get(rs) + ", " + imm; 43 | StringBuilder stringBuilder = new StringBuilder(sb); 44 | if (!super.getComment().equals("")) { 45 | stringBuilder.append("\t# ").append(super.getComment()); 46 | } 47 | sj.add(stringBuilder.toString()); 48 | return sj.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/back/instr/Subu.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Subu extends MipsInstr { 8 | private final int rd; 9 | private final int rt; 10 | private final int rs; 11 | 12 | public Subu(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRd() { 23 | return rd; 24 | } 25 | 26 | public int getRt() { 27 | return rt; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "subu " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Sw.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Sw extends MipsInstr { 8 | private final int rt; 9 | private final int base; 10 | private final int offset; 11 | 12 | public Sw(int rt, int offset, int base) { 13 | this.rt = rt; 14 | this.offset = offset; 15 | this.base = base; 16 | } 17 | 18 | public Sw(int rt, int offset, int base, String label) { 19 | super.setLabel(label); 20 | this.rt = rt; 21 | this.offset = offset; 22 | this.base = base; 23 | } 24 | 25 | public int getRt() { 26 | return rt; 27 | } 28 | 29 | public int getBase() { 30 | return base; 31 | } 32 | 33 | public int getOffset() { 34 | return offset; 35 | } 36 | 37 | public String toMips() { 38 | StringJoiner sj = new StringJoiner("\n"); 39 | sj.add(super.toMips()); 40 | String sb = "sw " + "$" + RF.ID_TO_NAME.get(rt) + ", " + 41 | offset + "(" + "$" + RF.ID_TO_NAME.get(base) + ")"; 42 | StringBuilder stringBuilder = new StringBuilder(sb); 43 | if (!super.getComment().equals("")) { 44 | stringBuilder.append("\t# ").append(super.getComment()); 45 | } 46 | sj.add(stringBuilder.toString()); 47 | return sj.toString(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/back/instr/Syscall.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import java.util.StringJoiner; 4 | 5 | public class Syscall extends MipsInstr { 6 | public Syscall() { 7 | 8 | } 9 | 10 | public String toMips() { 11 | StringJoiner sj = new StringJoiner("\n"); 12 | sj.add(super.toMips()); 13 | String sb = "syscall"; 14 | StringBuilder stringBuilder = new StringBuilder(sb); 15 | if (!super.getComment().equals("")) { 16 | stringBuilder.append("\t# ").append(super.getComment()); 17 | } 18 | sj.add(stringBuilder.toString()); 19 | return sj.toString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/back/instr/Xor.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Xor extends MipsInstr { 8 | private final int rd; 9 | private final int rt; 10 | private final int rs; 11 | 12 | public Xor(int rd, int rs, int rt) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.rt = rt; 16 | } 17 | 18 | public int getRs() { 19 | return rs; 20 | } 21 | 22 | public int getRd() { 23 | return rd; 24 | } 25 | 26 | public int getRt() { 27 | return rt; 28 | } 29 | 30 | public String toMips() { 31 | StringJoiner sj = new StringJoiner("\n"); 32 | sj.add(super.toMips()); 33 | String sb = "xor " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 34 | "$" + RF.ID_TO_NAME.get(rs) + ", " + "$" + RF.ID_TO_NAME.get(rt); 35 | StringBuilder stringBuilder = new StringBuilder(sb); 36 | if (!super.getComment().equals("")) { 37 | stringBuilder.append("\t# ").append(super.getComment()); 38 | } 39 | sj.add(stringBuilder.toString()); 40 | return sj.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/back/instr/Xori.java: -------------------------------------------------------------------------------- 1 | package back.instr; 2 | 3 | import back.hardware.RF; 4 | 5 | import java.util.StringJoiner; 6 | 7 | public class Xori extends MipsInstr { 8 | private final int rd; 9 | private final int rs; 10 | private final int imm; 11 | 12 | public Xori(int rd, int rs, int imm) { 13 | this.rd = rd; 14 | this.rs = rs; 15 | this.imm = imm; 16 | } 17 | 18 | public Xori(String label, int rd, int rs, int imm) { 19 | super.setLabel(label); 20 | this.rd = rd; 21 | this.rs = rs; 22 | this.imm = imm; 23 | } 24 | 25 | public int getImm() { 26 | return imm; 27 | } 28 | 29 | public int getRd() { 30 | return rd; 31 | } 32 | 33 | public int getRs() { 34 | return rs; 35 | } 36 | 37 | @Override 38 | public String toMips() { 39 | StringJoiner sj = new StringJoiner("\n"); 40 | sj.add(super.toMips()); 41 | String sb = "xori " + "$" + RF.ID_TO_NAME.get(rd) + ", " + 42 | "$" + RF.ID_TO_NAME.get(rs) + ", " + imm; 43 | StringBuilder stringBuilder = new StringBuilder(sb); 44 | if (!super.getComment().equals("")) { 45 | stringBuilder.append("\t# ").append(super.getComment()); 46 | } 47 | sj.add(stringBuilder.toString()); 48 | return sj.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/back/optimize/MultDiv.java: -------------------------------------------------------------------------------- 1 | package back.optimize; 2 | 3 | import back.hardware.RF; 4 | import back.instr.*; 5 | import util.Pair; 6 | 7 | public class MultDiv { 8 | 9 | 10 | public static MipsInstr betterMult(int dst, int n, int d) { 11 | int absd = d < 0 ? -d : d; 12 | if (absd == 1) { 13 | MipsInstr instr = new Move(dst, n); 14 | if (d < 0) { 15 | instr.append(new Subu(dst, RF.GPR.ZERO, dst)); 16 | } 17 | return instr; 18 | } else if (isTimesTwo(absd)) { 19 | int l = timesTwo(absd); 20 | MipsInstr inst = new Sll(dst, n, l); 21 | if (d < 0) { 22 | inst.append(new Subu(dst, RF.GPR.ZERO, dst)); 23 | } 24 | return inst; 25 | } else if (isTimesTwo(absd + 1)) { 26 | int l = timesTwo(absd + 1); 27 | MipsInstr inst = new Sll(dst, n, l); 28 | inst.append(new Subu(dst, dst, n)); 29 | if (d < 0) { 30 | inst.append(new Subu(dst, RF.GPR.ZERO, dst)); 31 | } 32 | return inst; 33 | } else if (isTimesTwo(absd - 1)) { 34 | int l = timesTwo(absd - 1); 35 | MipsInstr inst = new Sll(dst, n, l); 36 | inst.append(new Addu(dst, dst, n)); 37 | if (d < 0) { 38 | inst.append(new Subu(dst, RF.GPR.ZERO, dst)); 39 | } 40 | return inst; 41 | } 42 | MipsInstr noOpti = new Li(dst, d); 43 | noOpti.append(new Mul(dst, n, dst)); 44 | return noOpti; 45 | } 46 | 47 | public static MipsInstr betterDiv(int dst, int n, int d) { 48 | int absd = d < 0 ? -d : d; 49 | if (absd == 1) { 50 | MipsInstr instr = new Move(dst, n); 51 | if (d < 0) { 52 | instr.append(new Subu(dst, RF.GPR.ZERO, dst)); 53 | } 54 | return instr; 55 | } else if (isTimesTwo(absd)) { 56 | int l = timesTwo(absd); 57 | MipsInstr instr = new Sra(RF.GPR.V1, n, l - 1); 58 | instr.append(new Srl(RF.GPR.V1, RF.GPR.V1, 32 - l)); 59 | instr.append(new Addu(RF.GPR.V1, RF.GPR.V1, n)); 60 | instr.append(new Sra(dst, RF.GPR.V1, l)); 61 | if (d < 0) { 62 | instr.append(new Subu(dst, RF.GPR.ZERO, dst)); 63 | } 64 | return instr; 65 | } else { 66 | Pair ms = chooseMultiplier(absd, 31); 67 | long m = ms.o1; 68 | int shPost = ms.o2; 69 | if (m < ((long) 1 << 31)) { 70 | MipsInstr instr = new Li(dst, (int) m); 71 | instr.append(new Mult(dst, n)); 72 | instr.append(new Mfhi(dst)); 73 | instr.append(new Sra(dst, dst, shPost)); 74 | instr.append(new Sra(RF.GPR.V1, n, 31)); 75 | instr.append(new Subu(dst, dst, RF.GPR.V1)); 76 | if (d < 0) { 77 | instr.append(new Subu(dst, RF.GPR.ZERO, dst)); 78 | } 79 | return instr; 80 | } else { 81 | MipsInstr instr = new Li(dst, (int) (m - ((long) 1 << 32))); 82 | instr.append(new Mult(dst, n)); 83 | instr.append(new Mfhi(dst)); 84 | instr.append(new Addu(dst, dst, n)); 85 | instr.append(new Sra(dst, dst, shPost)); 86 | instr.append(new Sra(RF.GPR.V1, n, 31)); 87 | instr.append(new Subu(dst, dst, RF.GPR.V1)); 88 | if (d < 0) { 89 | instr.append(new Subu(dst, RF.GPR.ZERO, dst)); 90 | } 91 | return instr; 92 | } 93 | } 94 | } 95 | 96 | public static MipsInstr betterMod(int dst, int n, int d) { 97 | MipsInstr instr = betterDiv(dst, n, d); 98 | instr.append(new Move(RF.GPR.V1, dst)); 99 | instr.append(betterMult(dst, RF.GPR.V1, d)); 100 | instr.append(new Subu(dst, n, dst)); 101 | return instr; 102 | } 103 | 104 | public static boolean isTimesTwo(int n) { 105 | String str = Integer.toBinaryString(n); 106 | if (n < 1) { 107 | return false; 108 | } else { 109 | return str.lastIndexOf("1") == 0; 110 | } 111 | } 112 | 113 | public static int timesTwo(int n) { 114 | return Integer.toBinaryString(n).length() - 1; 115 | } 116 | 117 | public static Pair chooseMultiplier(int d, int prec) { 118 | int l = isTimesTwo(d) ? timesTwo(d) : timesTwo(d) + 1; 119 | int shPost = l; 120 | long mLow = ((long) 1 << (32 + l)) / d; 121 | long mHigh = (((long) 1 << (32 + l)) + ((long) 1 << (32 + l - prec))) / d; 122 | 123 | while ((mLow / 2) < (mHigh / 2) && shPost > 0) { 124 | mLow = mLow / 2; 125 | mHigh = mHigh / 2; 126 | shPost = shPost - 1; 127 | } 128 | return new Pair<>(mHigh, shPost); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/exception/CompileExc.java: -------------------------------------------------------------------------------- 1 | package exception; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | 7 | public class CompileExc extends Exception implements Comparable { 8 | private static final boolean DBG = true; 9 | 10 | public enum ErrCode { 11 | a, b, c, d, e, f, g, h, i, j, k, l, m 12 | } 13 | 14 | public enum ErrType { 15 | ILLEGAL_CHAR, 16 | REDEF, 17 | UNDECL, 18 | ARG_NUM_MISMATCH, 19 | ARG_TYPE_MISMATCH, 20 | RET_TYPE_MISMATCH, 21 | MISSING_RET, 22 | CHANGE_CONST, 23 | EXPECTED_SEMICN, 24 | EXPECTED_PARENT, 25 | EXPECTED_BRACK, 26 | FORMAT_VAR_ERR, 27 | NOT_IN_LOOP, 28 | 29 | } 30 | 31 | private static final Map TYPE_2_CODE = new HashMap() { 32 | { 33 | put(ErrType.ILLEGAL_CHAR, ErrCode.a); 34 | put(ErrType.REDEF, ErrCode.b); 35 | put(ErrType.UNDECL, ErrCode.c); 36 | put(ErrType.ARG_NUM_MISMATCH, ErrCode.d); 37 | put(ErrType.ARG_TYPE_MISMATCH, ErrCode.e); 38 | put(ErrType.RET_TYPE_MISMATCH, ErrCode.f); 39 | put(ErrType.MISSING_RET, ErrCode.g); 40 | put(ErrType.CHANGE_CONST, ErrCode.h); 41 | put(ErrType.EXPECTED_SEMICN, ErrCode.i); 42 | put(ErrType.EXPECTED_PARENT, ErrCode.j); 43 | put(ErrType.EXPECTED_BRACK, ErrCode.k); 44 | put(ErrType.FORMAT_VAR_ERR, ErrCode.l); 45 | put(ErrType.NOT_IN_LOOP, ErrCode.m); 46 | } 47 | }; 48 | 49 | private final ErrType errType; 50 | private int lineNo = 0; 51 | private final String msg; 52 | 53 | public CompileExc(ErrType errType, int lineNo, String msg) { 54 | this.errType = errType; 55 | this.lineNo = lineNo; 56 | this.msg = msg; 57 | } 58 | 59 | public CompileExc(ErrType errType, int lineNo) { 60 | this.errType = errType; 61 | this.lineNo = lineNo; 62 | this.msg = ""; 63 | } 64 | 65 | public CompileExc(ErrType errType, String msg) { 66 | this.errType = errType; 67 | this.msg = msg; 68 | } 69 | 70 | public void setLineNo(int lineNo) { 71 | this.lineNo = lineNo; 72 | } 73 | 74 | public String toString() { 75 | if (DBG) { 76 | return this.lineNo + " " + TYPE_2_CODE.get(this.errType).toString() + " " + errType.toString(); 77 | } 78 | return this.lineNo + " " + TYPE_2_CODE.get(this.errType).toString(); 79 | } 80 | 81 | @Override 82 | public int compareTo(CompileExc o) { 83 | return this.lineNo - o.lineNo; 84 | } 85 | 86 | @Override 87 | public boolean equals(Object o) { 88 | if (this == o) return true; 89 | if (o == null || getClass() != o.getClass()) return false; 90 | CompileExc that = (CompileExc) o; 91 | return lineNo == that.lineNo && errType == that.errType; 92 | } 93 | 94 | @Override 95 | public int hashCode() { 96 | return Objects.hash(errType, lineNo); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/exception/LexerExc.java: -------------------------------------------------------------------------------- 1 | package exception; 2 | 3 | public class LexerExc extends Exception{ 4 | } 5 | -------------------------------------------------------------------------------- /src/front/CompileUnit.java: -------------------------------------------------------------------------------- 1 | package front; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashSet; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | public class CompileUnit { 9 | private final String name; 10 | private final Type type; 11 | private final List childUnits; 12 | private final boolean isEnd; 13 | private final Integer lineNo; 14 | 15 | public enum Type { 16 | CompUnit, Decl, ConstDecl, BType, ConstDef, 17 | ConstInitVal, VarDecl, VarDef, FuncDef, MainFuncDef, FuncType, 18 | FuncFParams, FuncFParam, Block, BlockItem, Stmt, Exp, Cond, 19 | LVal, PrimaryExp, Number, UnaryExp, 20 | InitVal, 21 | UnaryOp, FuncRParams, MulExp, AddExp, RelExp, EqExp, LAndExp, LOrExp, ConstExp, 22 | MAINTK, CONSTTK, INTTK, BREAKTK, CONTINUETK, 23 | IFTK, ELSETK, 24 | WHILETK, 25 | GETINTTK, PRINTFTK, 26 | RETURNTK, VOIDTK, 27 | SINGLECOMMENT, MULTICOMMENT, 28 | PLUS, MINU, 29 | MULT, DIV, MOD, 30 | LEQ, GEQ, EQL, NEQ, 31 | AND, OR, 32 | NOT, LSS, GRE, ASSIGN, 33 | SEMICN, COMMA, 34 | LPARENT, RPARENT, 35 | LBRACK, RBRACK, 36 | LBRACE, RBRACE, 37 | IDENFR, INTCON, STRCON, 38 | WHITESPACE 39 | } 40 | 41 | public CompileUnit(String name, List unitList, Type type, boolean isEnd) { 42 | this.name = name; 43 | this.type = type; 44 | this.childUnits = unitList; 45 | this.isEnd = isEnd; 46 | this.lineNo = null; 47 | } 48 | 49 | public CompileUnit(String name, List unitList, Type type, boolean isEnd, Integer lineNo) { 50 | this.name = name; 51 | this.type = type; 52 | this.childUnits = unitList; 53 | this.isEnd = true; 54 | this.lineNo = lineNo; 55 | } 56 | 57 | public List childUnits() { 58 | return childUnits; 59 | } 60 | 61 | public Type type() { 62 | return type; 63 | } 64 | 65 | public String name() { 66 | return name; 67 | } 68 | 69 | public Integer lineNo() { 70 | return lineNo; 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | if (this.isEnd) { 76 | return type.toString() + " " + name; 77 | } else { 78 | String s = childUnits.stream().map(CompileUnit::toString) 79 | .collect(Collectors.joining("\n")); 80 | if (new HashSet<>(Arrays.asList(Type.BType, Type.Decl, Type.BlockItem)).contains(this.type)) { 81 | return s; 82 | } else { 83 | if (!s.equals("")) { 84 | return s + "\n<" + type.toString() + ">"; 85 | } else { 86 | return s + "<" + type.toString() + ">"; 87 | } 88 | } 89 | 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/front/FuncEntry.java: -------------------------------------------------------------------------------- 1 | package front; 2 | 3 | import exception.CompileExc; 4 | import front.nodes.FuncParamNode; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.StringJoiner; 11 | 12 | public class FuncEntry { 13 | 14 | private final String name;//函数名 15 | private final List args = new ArrayList<>();//参数表 16 | private final Map name2entry = new HashMap<>();//参数表 17 | private final boolean isMain;//是否是主函数 18 | private final TableEntry.ValueType returnType;//返回值类型 19 | 20 | public TableEntry.ValueType returnType() { 21 | return returnType; 22 | } 23 | 24 | public FuncEntry(String name, TableEntry.ValueType returnType) { 25 | this.name = name; 26 | this.returnType = returnType; 27 | this.isMain = false; 28 | } 29 | 30 | public String name() { 31 | return name; 32 | } 33 | 34 | public List args() { 35 | return args; 36 | } 37 | 38 | public Map name2entry() { 39 | return name2entry; 40 | } 41 | 42 | public void addArg(FuncParamNode funcParamNode) throws CompileExc { 43 | if (name2entry.containsKey(funcParamNode.ident())) { 44 | throw new CompileExc(CompileExc.ErrType.REDEF, funcParamNode.line()); 45 | } else { 46 | TableEntry tableEntry = new TableEntry(funcParamNode); 47 | name2entry.put(funcParamNode.ident(), tableEntry); 48 | args.add(tableEntry); 49 | } 50 | } 51 | 52 | 53 | public FuncEntry() { 54 | this.name = "main"; 55 | this.returnType = TableEntry.ValueType.INT; 56 | this.isMain = true; 57 | } 58 | 59 | public FuncEntry(String name, CompileUnit.Type type) { 60 | this.name = name; 61 | this.returnType = TableEntry.TO_VALUE_TYPE.get(type); 62 | this.isMain = name.equals("main"); 63 | } 64 | 65 | public String toIr() { 66 | StringBuilder sb = new StringBuilder(); 67 | sb.append("define dso_local "); 68 | sb.append(TableEntry.TO_IR.get(this.returnType)); 69 | sb.append(" @"); 70 | sb.append(name); 71 | sb.append("("); 72 | StringJoiner paramJoiner = new StringJoiner(","); 73 | for (TableEntry tableEntry : args) { 74 | paramJoiner.add(tableEntry.toParamIr()); 75 | } 76 | sb.append(paramJoiner.toString()); 77 | sb.append(")"); 78 | return sb.toString(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/front/SymbolTable.java: -------------------------------------------------------------------------------- 1 | package front; 2 | 3 | import exception.CompileExc; 4 | import front.nodes.DefNode; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class SymbolTable { 10 | private static final SymbolTable globalTable = new SymbolTable(null, "GLOBAL"); 11 | private final SymbolTable parentTable; 12 | private final String filedName; 13 | private final Map varSymbols = new HashMap<>(); 14 | 15 | 16 | public SymbolTable(SymbolTable parentTable, String filedName) { 17 | this.parentTable = parentTable; 18 | this.filedName = filedName; 19 | } 20 | 21 | public SymbolTable getParentTable() { 22 | return parentTable; 23 | } 24 | 25 | public boolean isGlobalTable() { 26 | return this.parentTable == null && this.filedName.equals("GLOBAL"); 27 | } 28 | 29 | public void addVarSymbol(DefNode defNode, int level, boolean isConst, CompileUnit.Type valueType) 30 | throws CompileExc { 31 | if (this.varSymbols.containsKey(defNode.ident())) { 32 | throw new CompileExc(CompileExc.ErrType.REDEF, defNode.line()); 33 | } else { 34 | TableEntry tableEntry = new TableEntry(defNode, isConst, level, valueType, isGlobalTable()); 35 | varSymbols.put(defNode.ident(), tableEntry); 36 | 37 | } 38 | } 39 | 40 | public void addVarSymbol(TableEntry tableEntry) { 41 | varSymbols.put(tableEntry.name, tableEntry); 42 | } 43 | 44 | public TableEntry getSymbol(String name) { 45 | if (varSymbols.containsKey(name)) { 46 | return varSymbols.get(name); 47 | } else if (this.parentTable != null) { 48 | return parentTable.getSymbol(name); 49 | } else { 50 | return null; 51 | } 52 | } 53 | 54 | public TableEntry getSymbolDefined(String name) { 55 | if (varSymbols.containsKey(name) && (varSymbols.get(name).defined || isGlobalTable())) { 56 | return varSymbols.get(name); 57 | } else if (this.parentTable != null) { 58 | return parentTable.getSymbol(name); 59 | } else { 60 | System.out.println("not find " + name); 61 | return null; 62 | } 63 | } 64 | 65 | public void setDefined(String name) { 66 | if (varSymbols.containsKey(name)) { 67 | varSymbols.get(name).setDefined(true); 68 | } 69 | } 70 | 71 | 72 | public String filedName() { 73 | return filedName; 74 | } 75 | 76 | public static SymbolTable globalTable() { 77 | return globalTable; 78 | } 79 | 80 | public Map getVarSymbols() { 81 | return varSymbols; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/front/Token.java: -------------------------------------------------------------------------------- 1 | package front; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | public class Token { 6 | public enum Type { 7 | MAINTK, CONSTTK, INTTK, BREAKTK, CONTINUETK, 8 | IFTK, ELSETK, 9 | WHILETK, 10 | GETINTTK, PRINTFTK, 11 | RETURNTK, VOIDTK, 12 | SINGLECOMMENT, MULTICOMMENT, 13 | PLUS, MINU, 14 | MULT, DIV, MOD, 15 | LEQ, GEQ, EQL, NEQ, 16 | AND, OR, 17 | NOT, LSS, GRE, ASSIGN, 18 | SEMICN, COMMA, 19 | LPARENT, RPARENT, 20 | LBRACK, RBRACK, 21 | LBRACE, RBRACE, 22 | IDENFR, INTCON, STRCON, 23 | WHITESPACE 24 | } 25 | 26 | public static final String MAINTK_P = "(?main(?![a-zA-Z0-9_]))"; 27 | public static final String CONSTTK_P = "(?const(?![a-zA-Z0-9_]))"; 28 | public static final String INTTK_P = "(?int(?![a-zA-Z0-9_]))"; 29 | public static final String BREAKTK_P = "(?break(?![a-zA-Z0-9_]))"; 30 | public static final String CONTINUETK_P = "(?continue(?![a-zA-Z0-9_]))"; 31 | public static final String IFTK_P = "(?if(?![a-zA-Z0-9_]))"; 32 | public static final String ELSETK_P = "(?else(?![a-zA-Z0-9_]))"; 33 | public static final String WHILETK_P = "(?while(?![a-zA-Z0-9_]))"; 34 | public static final String GETINTTK_P = "(?getint(?![a-zA-Z0-9_]))"; 35 | public static final String PRINTFTK_P = "(?printf(?![a-zA-Z0-9_]))"; 36 | public static final String RETURNTK_P = "(?return(?![a-zA-Z0-9_]))"; 37 | public static final String VOIDTK_P = "(?void(?![a-zA-Z0-9_]))"; 38 | public static final String SINGLECOMMENT_P = "(?//.*)"; 39 | public static final String MULTICOMMENT_P = "(?/\\*[\\s\\S]*?\\*/)"; 40 | public static final String PLUS_P = "(?\\+)"; 41 | public static final String MINU_P = "(?-)"; 42 | public static final String MULT_P = "(?\\*)"; 43 | public static final String DIV_P = "(?
/)"; 44 | public static final String MOD_P = "(?%)"; 45 | public static final String LEQ_P = "(?<=)"; 46 | public static final String GEQ_P = "(?>=)"; 47 | public static final String EQL_P = "(?==)"; 48 | public static final String NEQ_P = "(?!=)"; 49 | public static final String AND_P = "(?&&)"; 50 | public static final String OR_P = "(?\\|\\|)"; 51 | public static final String NOT_P = "(?!)"; 52 | public static final String LSS_P = "(?<)"; 53 | public static final String GRE_P = "(?>)"; 54 | public static final String ASSIGN_P = "(?=)"; 55 | public static final String SEMICN_P = "(?;)"; 56 | public static final String COMMA_P = "(?,)"; 57 | public static final String LPARENT_P = "(?\\()"; 58 | public static final String RPARENT_P = "(?\\))"; 59 | public static final String LBRACK_P = "(?\\[)"; 60 | public static final String RBRACK_P = "(?])"; 61 | public static final String LBRACE_P = "(?\\{)"; 62 | public static final String RBRACE_P = "(?})"; 63 | public static final String IDENFR_P = "(?[a-zA-Z_][a-zA-Z_0-9]*)"; 64 | public static final String INTCON_P = "(?[1-9][0-9]*|0)"; 65 | public static final String STRCON_P = "(?\".*?\")"; 66 | public static final String WHITESPACE_P = "(?\\s+)"; 67 | 68 | public static final Pattern TOKEN_PATTERN = Pattern.compile( 69 | MAINTK_P + "|" + 70 | CONSTTK_P + "|" + 71 | INTTK_P + "|" + 72 | BREAKTK_P + "|" + 73 | CONTINUETK_P + "|" + 74 | IFTK_P + "|" + 75 | ELSETK_P + "|" + 76 | WHILETK_P + "|" + 77 | GETINTTK_P + "|" + 78 | PRINTFTK_P + "|" + 79 | RETURNTK_P + "|" + 80 | VOIDTK_P + "|" + 81 | SINGLECOMMENT_P + "|" + 82 | MULTICOMMENT_P + "|" + 83 | PLUS_P + "|" + 84 | MINU_P + "|" + 85 | MULT_P + "|" + 86 | DIV_P + "|" + 87 | MOD_P + "|" + 88 | LEQ_P + "|" + 89 | GEQ_P + "|" + 90 | EQL_P + "|" + 91 | NEQ_P + "|" + 92 | AND_P + "|" + 93 | OR_P + "|" + 94 | NOT_P + "|" + 95 | LSS_P + "|" + 96 | GRE_P + "|" + 97 | ASSIGN_P + "|" + 98 | SEMICN_P + "|" + 99 | COMMA_P + "|" + 100 | LPARENT_P + "|" + 101 | RPARENT_P + "|" + 102 | LBRACK_P + "|" + 103 | RBRACK_P + "|" + 104 | LBRACE_P + "|" + 105 | RBRACE_P + "|" + 106 | IDENFR_P + "|" + 107 | INTCON_P + "|" + 108 | STRCON_P + "|" + 109 | WHITESPACE_P + "|" + 110 | "(?.)" 111 | 112 | ); 113 | 114 | public static boolean eat(Type type) { 115 | return type == Type.WHITESPACE || type == Type.SINGLECOMMENT || type == Type.MULTICOMMENT; 116 | } 117 | 118 | private final String stringInfo; 119 | private final Type type; 120 | private final int line; 121 | 122 | public Token(int line, Type type, String stringInfo) { 123 | this.stringInfo = stringInfo; 124 | this.type = type; 125 | this.line = line; 126 | } 127 | 128 | public int line() { 129 | return line; 130 | } 131 | 132 | public Type type() { 133 | return type; 134 | } 135 | 136 | public String stringInfo() { 137 | return stringInfo; 138 | } 139 | 140 | public String toString() { 141 | return this.type.toString() + " " + this.stringInfo; 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/front/TokenPackage.java: -------------------------------------------------------------------------------- 1 | package front; 2 | 3 | import java.util.List; 4 | 5 | public class TokenPackage { 6 | private int pointer; 7 | private final List tokenList; 8 | private Token curToken; 9 | 10 | public TokenPackage(List tokenList) { 11 | this.pointer = 0; 12 | this.tokenList = tokenList; 13 | this.curToken = null; 14 | this.next(); 15 | } 16 | 17 | public int getPointer() { 18 | return this.pointer; 19 | } 20 | 21 | public void setPointer(int pointer) { 22 | this.pointer = pointer; 23 | curToken = tokenList.get(pointer - 1); 24 | } 25 | 26 | public List getTokenList() { 27 | return tokenList; 28 | } 29 | 30 | public Token next() { 31 | if (pointer == tokenList.size()) { 32 | return null; 33 | } 34 | curToken = tokenList.get(pointer); 35 | pointer += 1; 36 | return tokenList.get(pointer - 1); 37 | } 38 | 39 | public Token preview(int offset) { 40 | if (pointer + offset > tokenList.size()) { 41 | return null; 42 | } 43 | return tokenList.get(pointer + offset - 1); 44 | } 45 | 46 | public Token getCurToken() { 47 | return curToken; 48 | } 49 | 50 | public Token previous() { 51 | if (pointer == 1) { 52 | return null; 53 | } 54 | pointer -= 1; 55 | this.curToken = tokenList.get(pointer - 1); 56 | return tokenList.get(pointer - 1); 57 | } 58 | 59 | public Token get(int index) { 60 | if (index < tokenList.size()) { 61 | return tokenList.get(index); 62 | } else { 63 | return null; 64 | } 65 | } 66 | 67 | public int sizeRemain() { 68 | return this.tokenList.size() - pointer; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/front/nodes/AssignNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | public class AssignNode implements StmtNode { 4 | private final LValNode lVal; 5 | private final ExprNode exprNode; 6 | 7 | public AssignNode(LValNode lVal, ExprNode exprNode) { 8 | this.lVal = lVal; 9 | this.exprNode = exprNode; 10 | } 11 | 12 | public ExprNode exprNode() { 13 | return exprNode; 14 | } 15 | 16 | public LValNode lVal() { 17 | return lVal; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "AssignNode{\n" + 23 | "lVal=" + lVal + 24 | ",\n exprNode=" + exprNode + 25 | "\n}"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/front/nodes/BinaryExpNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.CompileUnit; 4 | import front.SymbolTable; 5 | import front.TableEntry; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class BinaryExpNode extends ExprNode { 11 | public enum BinaryOp { 12 | ADD, SUB, MUL, DIV, MOD, 13 | LEQ, GEQ, EQL, NEQ, 14 | AND, OR, LSS, GRE 15 | } 16 | 17 | private static final Map TYPE_2_OP = new HashMap() { 18 | { 19 | put(CompileUnit.Type.PLUS, BinaryOp.ADD); 20 | put(CompileUnit.Type.MINU, BinaryOp.SUB); 21 | put(CompileUnit.Type.MULT, BinaryOp.MUL); 22 | put(CompileUnit.Type.DIV, BinaryOp.DIV); 23 | put(CompileUnit.Type.MOD, BinaryOp.MOD); 24 | put(CompileUnit.Type.LEQ, BinaryOp.LEQ); 25 | put(CompileUnit.Type.GEQ, BinaryOp.GEQ); 26 | put(CompileUnit.Type.EQL, BinaryOp.EQL); 27 | put(CompileUnit.Type.NEQ, BinaryOp.NEQ); 28 | put(CompileUnit.Type.AND, BinaryOp.AND); 29 | put(CompileUnit.Type.OR, BinaryOp.OR); 30 | put(CompileUnit.Type.LSS, BinaryOp.LSS); 31 | put(CompileUnit.Type.GRE, BinaryOp.GRE); 32 | } 33 | }; 34 | 35 | private final BinaryOp op; 36 | private final ExprNode left; 37 | private final ExprNode right; 38 | 39 | public BinaryExpNode(ExprNode left, BinaryOp op, ExprNode right) { 40 | super.valueType = (left.valueType == TableEntry.ValueType.INT && right.valueType == TableEntry.ValueType.INT) ? 41 | TableEntry.ValueType.INT : TableEntry.ValueType.VOID; 42 | super.dimension = Math.max(left.dimension, right.dimension); 43 | this.op = op; 44 | this.left = left; 45 | this.right = right; 46 | } 47 | 48 | public BinaryExpNode(ExprNode left, CompileUnit.Type type, ExprNode right) { 49 | super.valueType = (left.valueType == TableEntry.ValueType.INT && right.valueType == TableEntry.ValueType.INT) ? 50 | TableEntry.ValueType.INT : TableEntry.ValueType.VOID; 51 | super.dimension = Math.max(left.dimension, right.dimension); 52 | this.op = TYPE_2_OP.get(type); 53 | this.left = left; 54 | this.right = right; 55 | } 56 | 57 | public BinaryOp op() { 58 | return op; 59 | } 60 | 61 | public ExprNode left() { 62 | return left; 63 | } 64 | 65 | public ExprNode right() { 66 | return right; 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return "BinaryExpNode{\n" + 72 | "op=" + op + 73 | ",\n left=" + left + 74 | ",\n right=" + right + 75 | "\n}"; 76 | } 77 | 78 | @Override 79 | public ExprNode simplify(SymbolTable symbolTable) { 80 | ExprNode simplifiedLeft = left.simplify(symbolTable); 81 | ExprNode simplifiedRight = right.simplify(symbolTable); 82 | 83 | if (simplifiedLeft instanceof NumberNode && 84 | simplifiedRight instanceof NumberNode) { 85 | switch (op) { 86 | case ADD: 87 | return new NumberNode(((NumberNode) simplifiedLeft).number() 88 | + ((NumberNode) simplifiedRight).number()); 89 | case SUB: 90 | return new NumberNode(((NumberNode) simplifiedLeft).number() 91 | - ((NumberNode) simplifiedRight).number()); 92 | case MUL: 93 | return new NumberNode(((NumberNode) simplifiedLeft).number() 94 | * ((NumberNode) simplifiedRight).number()); 95 | case DIV: 96 | return new NumberNode(((NumberNode) simplifiedLeft).number() 97 | / ((NumberNode) simplifiedRight).number()); 98 | case MOD: 99 | return new NumberNode(((NumberNode) simplifiedLeft).number() 100 | % ((NumberNode) simplifiedRight).number()); 101 | case EQL: 102 | return new NumberNode(((NumberNode) simplifiedLeft).number() 103 | == ((NumberNode) simplifiedRight).number() ? 1 : 0); 104 | case GEQ: 105 | return new NumberNode(((NumberNode) simplifiedLeft).number() 106 | >= ((NumberNode) simplifiedRight).number() ? 1 : 0); 107 | case GRE: 108 | return new NumberNode(((NumberNode) simplifiedLeft).number() 109 | > ((NumberNode) simplifiedRight).number() ? 1 : 0); 110 | case LEQ: 111 | return new NumberNode(((NumberNode) simplifiedLeft).number() 112 | <= ((NumberNode) simplifiedRight).number() ? 1 : 0); 113 | case LSS: 114 | return new NumberNode(((NumberNode) simplifiedLeft).number() 115 | < ((NumberNode) simplifiedRight).number() ? 1 : 0); 116 | case NEQ: 117 | return new NumberNode(((NumberNode) simplifiedLeft).number() 118 | != ((NumberNode) simplifiedRight).number() ? 1 : 0); 119 | case OR: 120 | return new NumberNode(((NumberNode) simplifiedLeft).number() != 0 || 121 | ((NumberNode) simplifiedRight).number() != 0 ? 1 : 0); 122 | case AND: 123 | return new NumberNode(((NumberNode) simplifiedLeft).number() != 0 && 124 | ((NumberNode) simplifiedRight).number() != 0 ? 1 : 0); 125 | default: 126 | return new BinaryExpNode(simplifiedLeft, op, simplifiedRight); 127 | } 128 | } else { 129 | return new BinaryExpNode(simplifiedLeft, op, simplifiedRight); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/front/nodes/BlockItemNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | public interface BlockItemNode extends SyntaxNode { 4 | 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/front/nodes/BlockNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.FuncEntry; 4 | import front.SymbolTable; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class BlockNode implements StmtNode { 10 | private final List blockItemNodes; 11 | private final BlockType type; 12 | private SymbolTable symbolTable = null; 13 | private FuncEntry funcEntry = null; 14 | private int depth = 0; 15 | 16 | public enum BlockType { 17 | FUNC, BRANCH, LOOP, BASIC 18 | } 19 | 20 | public BlockType type() { 21 | return type; 22 | } 23 | 24 | public BlockNode(List blockItemNodes, BlockType type) { 25 | this.blockItemNodes = blockItemNodes; 26 | this.type = type; 27 | } 28 | 29 | public BlockNode(BlockItemNode blockItemNode, BlockType type, int depth, SymbolTable symbolTable) { 30 | this.blockItemNodes = new ArrayList() { 31 | { 32 | add(blockItemNode); 33 | } 34 | }; 35 | this.type = type; 36 | this.depth = depth; 37 | this.symbolTable = symbolTable; 38 | } 39 | 40 | public BlockNode(List blockItemNode, BlockType type, int depth, SymbolTable symbolTable) { 41 | this.blockItemNodes = blockItemNode; 42 | this.type = type; 43 | this.depth = depth; 44 | this.symbolTable = symbolTable; 45 | } 46 | 47 | public List blockItemNodes() { 48 | return blockItemNodes; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "BlockNode{\n" + 54 | "blockItemNodes=" + blockItemNodes + 55 | "\n}"; 56 | } 57 | 58 | public FuncEntry getFuncEntry() { 59 | return funcEntry; 60 | } 61 | 62 | public SymbolTable getSymbolTable() { 63 | return symbolTable; 64 | } 65 | 66 | public void setFuncEntry(FuncEntry funcEntry) { 67 | this.funcEntry = funcEntry; 68 | } 69 | 70 | public void setSymbolTable(SymbolTable symbolTable) { 71 | this.symbolTable = symbolTable; 72 | } 73 | 74 | public void setDepth(int depth) { 75 | this.depth = depth; 76 | } 77 | 78 | public int getDepth() { 79 | return depth; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/front/nodes/BreakStmtNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | public class BreakStmtNode implements StmtNode { 4 | private final int line; 5 | 6 | public BreakStmtNode(int line) { 7 | this.line = line; 8 | } 9 | 10 | public int line() { 11 | return line; 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return "BreakStmtNode{\n" + 17 | "line=" + line + 18 | "\n}"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/front/nodes/CompileUnitNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import java.util.List; 4 | 5 | public class CompileUnitNode implements SyntaxNode { 6 | private final List declNodes; 7 | private final List funcDefNodes; 8 | private final FuncDefNode mainFuncDef; 9 | 10 | public CompileUnitNode(List declNodes, List funcDefNodes, FuncDefNode mainFuncDef) { 11 | this.declNodes = declNodes; 12 | this.funcDefNodes = funcDefNodes; 13 | this.mainFuncDef = mainFuncDef; 14 | } 15 | 16 | public List declNodes() { 17 | return declNodes; 18 | } 19 | 20 | public List funcDefNodes() { 21 | return funcDefNodes; 22 | } 23 | 24 | public FuncDefNode mainFuncDef() { 25 | return mainFuncDef; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return "CompileUnitNode{\n" + 31 | "declNodes=" + declNodes + 32 | ",\n funcDefNodes=" + funcDefNodes + 33 | ",\n mainFuncDef=" + mainFuncDef + 34 | "\n}"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/front/nodes/ContinueStmtNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | public class ContinueStmtNode implements StmtNode { 4 | private final int line; 5 | 6 | public ContinueStmtNode(int line) { 7 | this.line = line; 8 | } 9 | 10 | public int line() { 11 | return line; 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return "ContinueStmtNode{\n" + 17 | "line=" + line + 18 | "\n}"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/front/nodes/DeclNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.CompileUnit; 4 | 5 | import java.util.List; 6 | 7 | public class DeclNode implements BlockItemNode { 8 | private final boolean isConst; 9 | private final CompileUnit.Type type; 10 | private final List defNodeList; 11 | 12 | public DeclNode(boolean isConst, CompileUnit.Type type, List defNodeList) { 13 | this.isConst = isConst; 14 | this.type = type; 15 | this.defNodeList = defNodeList; 16 | } 17 | 18 | public boolean isConst() { 19 | return isConst; 20 | } 21 | 22 | public List defNodeList() { 23 | return defNodeList; 24 | } 25 | 26 | public CompileUnit.Type getType() { 27 | return type; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "DeclNode{\n" + 33 | "isConst=" + isConst + 34 | ",\n type=" + type + 35 | ",\n defNodeList=" + defNodeList + 36 | "\n}"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/front/nodes/DefNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.Token; 4 | 5 | import java.util.List; 6 | 7 | public class DefNode implements SyntaxNode { 8 | private final String ident; 9 | private final int line; 10 | private final List dimension; 11 | private final List initValues; 12 | 13 | public DefNode(String ident, int line, List dimension, List initValues) { 14 | this.ident = ident; 15 | this.line = line; 16 | this.dimension = dimension; 17 | this.initValues = initValues; 18 | } 19 | 20 | public List dimension() { 21 | return dimension; 22 | } 23 | 24 | public List initValues() { 25 | return initValues; 26 | } 27 | 28 | public int line() { 29 | return line; 30 | } 31 | 32 | public String ident() { 33 | return ident; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "DefNode{\n" + 39 | "ident='" + ident + '\'' + 40 | ",\n line=" + line + 41 | ",\n dimension=" + dimension + 42 | ",\n initValues=" + initValues + 43 | "\n}"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/front/nodes/EmptyStmtNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | public class EmptyStmtNode implements StmtNode { 4 | 5 | public String toString() { 6 | return "emptyStmt;"; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/front/nodes/ExprNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.SymbolTable; 4 | import front.TableEntry; 5 | 6 | public abstract class ExprNode implements StmtNode { 7 | public TableEntry.ValueType valueType; 8 | public int dimension; 9 | 10 | public abstract ExprNode simplify(SymbolTable symbolTable); 11 | } 12 | -------------------------------------------------------------------------------- /src/front/nodes/FuncCallNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.SymbolTable; 4 | import front.TableEntry; 5 | 6 | import java.util.List; 7 | 8 | public class FuncCallNode extends ExprNode { 9 | private final String ident; 10 | private final int line; 11 | private final List args; 12 | 13 | public FuncCallNode(String ident, int line, List args, TableEntry.ValueType type) { 14 | super.valueType = type; 15 | super.dimension = 0; 16 | this.ident = ident; 17 | this.line = line; 18 | this.args = args; 19 | } 20 | 21 | public int line() { 22 | return line; 23 | } 24 | 25 | public String ident() { 26 | return ident; 27 | } 28 | 29 | public List args() { 30 | return args; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "FuncCallNode{\n" + 36 | "ident='" + ident + '\'' + 37 | ",\n line=" + line + 38 | ",\n args=" + args + 39 | "\n}"; 40 | } 41 | 42 | @Override 43 | public ExprNode simplify(SymbolTable symbolTable) { 44 | return this; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/front/nodes/FuncDefNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.CompileUnit; 4 | 5 | import java.util.List; 6 | 7 | public class FuncDefNode implements SyntaxNode { 8 | private final CompileUnit.Type type; 9 | private final String name; 10 | private final int line; 11 | private final List funcParams; 12 | private final BlockNode blockNode; 13 | 14 | public CompileUnit.Type type() { 15 | return type; 16 | } 17 | 18 | public String name() { 19 | return name; 20 | } 21 | 22 | public List funcParams() { 23 | return funcParams; 24 | } 25 | 26 | public BlockNode blockNode() { 27 | return blockNode; 28 | } 29 | 30 | public int line() { 31 | return line; 32 | } 33 | 34 | public FuncDefNode(CompileUnit.Type type, String name, int line, List funcParams, BlockNode blockNode) { 35 | this.type = type; 36 | this.name = name; 37 | this.line = line; 38 | this.funcParams = funcParams; 39 | this.blockNode = blockNode; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "FuncDefNode{\n" + 45 | "type=" + type + 46 | ",\n name='" + name + '\'' + 47 | ",\n line=" + line + 48 | ",\n funcParams=" + funcParams + 49 | ",\n blockNode=" + blockNode + 50 | "\n}"; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/front/nodes/FuncParamNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.CompileUnit; 4 | 5 | import java.util.List; 6 | 7 | public class FuncParamNode implements SyntaxNode { 8 | private final CompileUnit.Type type; 9 | private final String ident; 10 | private final int line; 11 | private final List dimension; 12 | 13 | public FuncParamNode(CompileUnit.Type type, String name, int line, List dimension) { 14 | this.type = type; 15 | this.ident = name; 16 | this.line = line; 17 | this.dimension = dimension; 18 | } 19 | 20 | public CompileUnit.Type type() { 21 | return type; 22 | } 23 | 24 | public int line() { 25 | return line; 26 | } 27 | 28 | public List dimension() { 29 | return dimension; 30 | } 31 | 32 | public String ident() { 33 | return ident; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "FuncParamNode{\n" + 39 | "type=" + type + 40 | ",\n ident='" + ident + '\'' + 41 | ",\n line=" + line + 42 | ",\n dimension=" + dimension + 43 | "\n}"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/front/nodes/GetintNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.SymbolTable; 4 | import front.TableEntry; 5 | 6 | import java.util.Collections; 7 | 8 | public class GetintNode extends FuncCallNode { 9 | public GetintNode(int line) { 10 | super("getInt", line, Collections.emptyList(), TableEntry.ValueType.INT); 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return "getint();"; 16 | } 17 | 18 | @Override 19 | public ExprNode simplify(SymbolTable symbolTable) { 20 | return this; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/front/nodes/IfNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.SymbolTable; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class IfNode implements StmtNode { 8 | private ExprNode cond; 9 | private final BlockNode ifStmt; 10 | private final BlockNode elseStmt; 11 | 12 | public IfNode(ExprNode cond, BlockNode ifStmt, BlockNode elseStmt) { 13 | this.cond = cond; 14 | this.ifStmt = ifStmt; 15 | this.elseStmt = elseStmt; 16 | } 17 | 18 | public IfNode(ExprNode cond, BlockNode ifStmt) { 19 | this.cond = cond; 20 | this.ifStmt = ifStmt; 21 | this.elseStmt = null; 22 | } 23 | 24 | public ExprNode cond() { 25 | return cond; 26 | } 27 | 28 | public BlockNode ifStmt() { 29 | return ifStmt; 30 | } 31 | 32 | public BlockNode elseStmt() { 33 | return elseStmt; 34 | } 35 | 36 | public void setCond(ExprNode cond) { 37 | this.cond = cond; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "IfNode{\n" + 43 | "cond=" + cond + 44 | ",\n ifStmt=" + ifStmt + 45 | ",\n elseStmt=" + elseStmt + 46 | "\n}"; 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/front/nodes/LValNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.SymbolTable; 4 | import front.TableEntry; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class LValNode extends ExprNode { 10 | private final String ident; 11 | private final int line; 12 | private final List index; 13 | 14 | public LValNode(String ident, int line, List index, int dimension, TableEntry.ValueType valueType) { 15 | super.dimension = dimension - index.size(); 16 | super.valueType = valueType; 17 | this.ident = ident; 18 | this.line = line; 19 | this.index = index; 20 | } 21 | 22 | public LValNode(int dimension, TableEntry.ValueType valueType, String ident, int line, List index) { 23 | super.dimension = dimension; 24 | super.valueType = valueType; 25 | this.ident = ident; 26 | this.line = line; 27 | this.index = index; 28 | } 29 | 30 | public int line() { 31 | return line; 32 | } 33 | 34 | public List index() { 35 | return index; 36 | } 37 | 38 | public String ident() { 39 | return ident; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "LValNode{\n" + 45 | "ident='" + ident + '\'' + 46 | ", \nline=" + line + 47 | ",\n index=" + index + 48 | "\n}"; 49 | } 50 | 51 | @Override 52 | public ExprNode simplify(SymbolTable symbolTable) { 53 | List simplifiedIndex = new ArrayList<>(); 54 | for (ExprNode exprNode : index) { 55 | simplifiedIndex.add(exprNode.simplify(symbolTable)); 56 | } 57 | TableEntry tableEntry = symbolTable.getSymbolDefined(this.ident); 58 | if (tableEntry != null && tableEntry.isConst && this.dimension == 0) { 59 | for (ExprNode exprNode : simplifiedIndex) { 60 | if (!(exprNode instanceof NumberNode)) { 61 | return new LValNode(dimension, valueType, ident, line, simplifiedIndex); 62 | } 63 | } 64 | for (ExprNode exprNode : tableEntry.dimension) { 65 | if (!(exprNode instanceof NumberNode)) { 66 | return new LValNode(dimension, valueType, ident, line, simplifiedIndex); 67 | } 68 | } 69 | if (tableEntry.refType == TableEntry.RefType.ITEM) { 70 | if (tableEntry.initValue instanceof NumberNode) { 71 | return new NumberNode(((NumberNode) tableEntry.initValue).number()); 72 | } else { 73 | return new LValNode(dimension, valueType, ident, line, simplifiedIndex); 74 | } 75 | } else if (tableEntry.refType == TableEntry.RefType.ARRAY) { 76 | int position = 0; 77 | for (int i = 0; i < simplifiedIndex.size(); i++) { 78 | int temp = ((NumberNode) simplifiedIndex.get(i)).number(); 79 | for (int j = i + 1; j < tableEntry.dimension.size(); 80 | j++) { 81 | temp = temp * ((NumberNode) tableEntry.dimension.get(j)).number(); 82 | } 83 | position += temp; 84 | } 85 | if (tableEntry.initValueList.get(position) instanceof NumberNode) { 86 | return new NumberNode(((NumberNode) tableEntry.initValueList.get(position)).number()); 87 | } else { 88 | return new LValNode(dimension, valueType, ident, line, simplifiedIndex); 89 | } 90 | } else { 91 | return new LValNode(dimension, valueType, ident, line, simplifiedIndex); 92 | } 93 | 94 | } else { 95 | return new LValNode(dimension, valueType, ident, line, simplifiedIndex); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/front/nodes/NumberNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.SymbolTable; 4 | import front.TableEntry; 5 | import mid.ircode.Operand; 6 | 7 | public class NumberNode extends ExprNode { 8 | private final int number; 9 | 10 | public NumberNode(int number) { 11 | super.valueType = TableEntry.ValueType.INT; 12 | super.dimension = 0; 13 | this.number = number; 14 | } 15 | 16 | public int number() { 17 | return number; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "NumberNode{\n" + 23 | "number=" + number + 24 | "\n}"; 25 | } 26 | 27 | @Override 28 | public ExprNode simplify(SymbolTable symbolTable) { 29 | return this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/front/nodes/PrintfNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import exception.CompileExc; 4 | import front.SymbolTable; 5 | import front.TableEntry; 6 | 7 | import java.util.List; 8 | 9 | public class PrintfNode extends FuncCallNode { 10 | private final String formatString; 11 | 12 | public PrintfNode(int line, String formatString, List args) { 13 | super("printf", line, args, TableEntry.ValueType.VOID); 14 | this.formatString = formatString.replace("\"", ""); 15 | } 16 | 17 | public String formatString() { 18 | return formatString; 19 | } 20 | 21 | public void checkArgNum() throws CompileExc { 22 | if (("\"" + formatString + "\"").split("%d").length - 1 != super.args().size()) { 23 | throw new CompileExc(CompileExc.ErrType.FORMAT_VAR_ERR, super.line()); 24 | } 25 | } 26 | 27 | public void checkFormatString() throws CompileExc { 28 | for (int i = 0; i < formatString.length(); i++) { 29 | int asc = (int) formatString.charAt(i); 30 | if (asc == 92 && (i == formatString.length() - 1 || formatString.charAt(i + 1) != 'n')) { 31 | throw new CompileExc(CompileExc.ErrType.ILLEGAL_CHAR, super.line()); 32 | } 33 | if (asc == 37 && (i == formatString.length() - 1 || formatString.charAt(i + 1) != 'd')) { 34 | throw new CompileExc(CompileExc.ErrType.ILLEGAL_CHAR, super.line()); 35 | } 36 | if (!(asc == 32 || asc == 33 || asc == 37 || (asc >= 40 && asc <= 126))) { 37 | throw new CompileExc(CompileExc.ErrType.ILLEGAL_CHAR, super.line()); 38 | } 39 | } 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "PrintfNode{\n" + 45 | super.toString() + 46 | "formatString='" + formatString + '\'' + 47 | "\n}"; 48 | } 49 | 50 | @Override 51 | public ExprNode simplify(SymbolTable symbolTable) { 52 | return this; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/front/nodes/ReturnNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | public class ReturnNode implements StmtNode { 4 | private final int line; 5 | private final ExprNode returnExpr; 6 | 7 | public ReturnNode(int line, ExprNode returnExpr) { 8 | this.line = line; 9 | this.returnExpr = returnExpr; 10 | } 11 | 12 | public int line() { 13 | return line; 14 | } 15 | 16 | public ExprNode returnExpr() { 17 | return returnExpr; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "ReturnNode{\n" + 23 | "line=" + line + 24 | ",\n returnExpr=" + returnExpr + 25 | "\n}"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/front/nodes/StmtNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import mid.ircode.BasicBlock; 4 | 5 | import java.util.List; 6 | 7 | public interface StmtNode extends BlockItemNode { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/front/nodes/SyntaxNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | public interface SyntaxNode { 4 | 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/front/nodes/UnaryExpNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | import front.CompileUnit; 4 | import front.SymbolTable; 5 | 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class UnaryExpNode extends ExprNode { 11 | public enum UnaryOp { 12 | PLUS, MINU, NOT 13 | } 14 | 15 | private static final Map TYPE_2_OP = new HashMap() { 16 | { 17 | put(CompileUnit.Type.PLUS, UnaryOp.PLUS); 18 | put(CompileUnit.Type.MINU, UnaryOp.MINU); 19 | put(CompileUnit.Type.NOT, UnaryOp.NOT); 20 | } 21 | }; 22 | 23 | private final UnaryOp op; 24 | private final ExprNode expNode; 25 | 26 | 27 | public UnaryExpNode(CompileUnit.Type type, ExprNode exprNode) { 28 | super.valueType = exprNode.valueType; 29 | super.dimension = exprNode.dimension; 30 | this.op = TYPE_2_OP.get(type); 31 | this.expNode = exprNode; 32 | } 33 | 34 | public UnaryExpNode(UnaryOp op, ExprNode exprNode) { 35 | this.op = op; 36 | this.expNode = exprNode; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return "UnaryExpNode{\n" + 42 | "op=" + op + 43 | ",\n expNode=" + expNode + 44 | "\n}"; 45 | } 46 | 47 | public UnaryOp op() { 48 | return op; 49 | } 50 | 51 | public ExprNode expNode() { 52 | return expNode; 53 | } 54 | 55 | @Override 56 | public ExprNode simplify(SymbolTable symbolTable) { 57 | ExprNode simplifiedExpNode = expNode.simplify(symbolTable); 58 | if (simplifiedExpNode instanceof NumberNode) { 59 | switch (op) { 60 | case NOT: 61 | return new NumberNode(((NumberNode) simplifiedExpNode).number() != 0 ? 0 : 1); 62 | case MINU: 63 | return new NumberNode(((NumberNode) simplifiedExpNode).number() * -1); 64 | case PLUS: 65 | return new NumberNode(((NumberNode) simplifiedExpNode).number()); 66 | default: 67 | return new UnaryExpNode(op, simplifiedExpNode); 68 | } 69 | } else { 70 | return new UnaryExpNode(op,simplifiedExpNode); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/front/nodes/WhileNode.java: -------------------------------------------------------------------------------- 1 | package front.nodes; 2 | 3 | public class WhileNode implements StmtNode { 4 | private ExprNode cond; 5 | private final BlockNode whileStmt; 6 | 7 | public WhileNode(ExprNode cond, BlockNode whileStmt) { 8 | this.cond = cond; 9 | this.whileStmt = whileStmt; 10 | } 11 | 12 | public ExprNode cond() { 13 | return cond; 14 | } 15 | 16 | public BlockNode whileStmt() { 17 | return whileStmt; 18 | } 19 | 20 | public void setCond(ExprNode cond) { 21 | this.cond = cond; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return "WhileNode{\n" + 27 | "cond=" + cond + 28 | ", \nwhileStmt=" + whileStmt + 29 | "\n}"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/mid/IrModule.java: -------------------------------------------------------------------------------- 1 | package mid; 2 | 3 | import front.TableEntry; 4 | import mid.ircode.FuncDef; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.StringJoiner; 9 | 10 | public class IrModule { 11 | private final List targetInformation = new ArrayList() { 12 | { 13 | add("declare i32 @getint()"); 14 | add("declare void @putint(i32)"); 15 | add("declare void @putch(i32)"); 16 | add("declare void @putstr(i8*)"); 17 | } 18 | }; 19 | private final List globalVarDefs = new ArrayList<>(); 20 | private final List funcDefs = new ArrayList<>(); 21 | 22 | public IrModule(){ 23 | 24 | } 25 | public List getFuncDefs() { 26 | return funcDefs; 27 | } 28 | 29 | public List getTargetInformation() { 30 | return targetInformation; 31 | } 32 | 33 | public List getGlobalVarDefs() { 34 | return globalVarDefs; 35 | } 36 | 37 | public String toIr() { 38 | StringJoiner sj = new StringJoiner("\n"); 39 | for (String str : targetInformation) { 40 | sj.add(str); 41 | } 42 | for (TableEntry tableEntry : globalVarDefs) { 43 | sj.add(tableEntry.toGlobalIr()); 44 | } 45 | for (FuncDef funcDef : funcDefs) { 46 | sj.add(funcDef.toIr()); 47 | } 48 | return sj.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/mid/LabelCounter.java: -------------------------------------------------------------------------------- 1 | package mid; 2 | 3 | public class LabelCounter { 4 | private static int labelCounter = -1; 5 | 6 | public static String getLabel() { 7 | labelCounter += 1; 8 | return "label_" + labelCounter; 9 | } 10 | 11 | public static String getLabel(String tag) { 12 | labelCounter += 1; 13 | return tag + "_label_" + labelCounter; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/mid/StringCounter.java: -------------------------------------------------------------------------------- 1 | package mid; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class StringCounter { 7 | private static final Map STR_2_LABEL = new HashMap<>(); 8 | private static int labelCounter = 0; 9 | 10 | public static String findString(String str) { 11 | if (!STR_2_LABEL.containsKey(str)) { 12 | STR_2_LABEL.put(str, "str" + labelCounter); 13 | labelCounter += 1; 14 | return STR_2_LABEL.get(str); 15 | } else { 16 | return STR_2_LABEL.get(str); 17 | } 18 | } 19 | 20 | public static int getLabelCounter() { 21 | return labelCounter; 22 | } 23 | 24 | public static Map getStr2Label() { 25 | return STR_2_LABEL; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/mid/TempCounter.java: -------------------------------------------------------------------------------- 1 | package mid; 2 | 3 | import front.TableEntry; 4 | import front.nodes.ExprNode; 5 | import front.nodes.NumberNode; 6 | import mid.ircode.Operand; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class TempCounter { 12 | private static int counter = -1; 13 | 14 | public static TableEntry getTemp(TableEntry.RefType refType, TableEntry.ValueType valueType) { 15 | counter += 1; 16 | return new TableEntry(refType, valueType, "%-t" + counter, null, false, 0, false, true); 17 | } 18 | 19 | public static TableEntry getTemp() { 20 | counter += 1; 21 | TableEntry tableEntry = new TableEntry(TableEntry.RefType.ITEM, TableEntry.ValueType.INT, 22 | "-t" + counter, 0, false, 0, false, true); 23 | tableEntry.setDefined(true); 24 | return tableEntry; 25 | } 26 | 27 | public static TableEntry getTempPointer(TableEntry base, List indexs) { 28 | counter += 1; 29 | List dim = new ArrayList<>(); 30 | dim.add(new NumberNode(0)); 31 | dim.addAll(base.dimension); 32 | for (int i = 1; i < indexs.size(); i++) { 33 | dim.remove(1); 34 | } 35 | 36 | TableEntry tableEntry = new TableEntry(TableEntry.RefType.POINTER, TableEntry.ValueType.INT, 37 | "-t" + counter, dim); 38 | tableEntry.setDefined(true); 39 | return tableEntry; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/mid/ircode/BasicBlock.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import java.util.HashSet; 4 | import java.util.StringJoiner; 5 | 6 | public class BasicBlock extends InstructionLinkNode { 7 | private static int ID_COUNTER = 0; 8 | private final int id; 9 | private final String beginLabel; 10 | private final InstructionLinkNode end = new InstructionLinkNode(); 11 | private String endLabel; 12 | private final HashSet prevBlock = new HashSet<>(); 13 | private final HashSet nextBlock = new HashSet<>(); 14 | 15 | public BasicBlock(String label) { 16 | this.id = ID_COUNTER; 17 | ID_COUNTER += 1; 18 | this.beginLabel = label; 19 | this.setNext(this.end); 20 | this.end.setPrev(this); 21 | this.endLabel = null; 22 | } 23 | 24 | public String getLabel() { 25 | return beginLabel; 26 | } 27 | 28 | public InstructionLinkNode getFirstInstruction() { 29 | return this.next(); 30 | } 31 | 32 | public InstructionLinkNode getLastInstruction() { 33 | return end.prev(); 34 | } 35 | 36 | public void addAfter(InstructionLinkNode instruct) { 37 | InstructionLinkNode last = getLastInstruction(); 38 | last.setNext(instruct); 39 | instruct.setPrev(last); 40 | InstructionLinkNode ptr = instruct; 41 | while (ptr.hasNext()) { 42 | ptr = ptr.next(); 43 | } 44 | end.setPrev(ptr); 45 | ptr.setNext(end); 46 | } 47 | 48 | public String toIr() { 49 | StringJoiner sj = new StringJoiner("\n"); 50 | sj.add(beginLabel + ":"); 51 | InstructionLinkNode ptr = this.next(); 52 | while (ptr != this.end) { 53 | sj.add(ptr.toIr()); 54 | ptr = ptr.next(); 55 | } 56 | if (endLabel != null) { 57 | sj.add(endLabel + ":"); 58 | } 59 | return sj.toString(); 60 | } 61 | 62 | public InstructionLinkNode getEnd() { 63 | return end; 64 | } 65 | 66 | public String getEndLabel() { 67 | return endLabel; 68 | } 69 | 70 | public String getBeginLabel() { 71 | return beginLabel; 72 | } 73 | 74 | public void setEndLabel(String endLabel) { 75 | this.endLabel = endLabel; 76 | } 77 | 78 | public int getId() { 79 | return id; 80 | } 81 | 82 | public HashSet getNextBlock() { 83 | return nextBlock; 84 | } 85 | 86 | public HashSet getPrevBlock() { 87 | return prevBlock; 88 | } 89 | 90 | public void addPrevBlock(String id) { 91 | this.prevBlock.add(id); 92 | } 93 | 94 | public void addNextBlock(String id) { 95 | this.nextBlock.add(id); 96 | } 97 | 98 | public boolean isEmpty() { 99 | return getFirstInstruction() == end; 100 | } 101 | 102 | public void removeInstr(InstructionLinkNode instr) { 103 | instr.prev().setNext(instr.next()); 104 | instr.next().setPrev(instr.prev()); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/mid/ircode/BinaryOperator.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | import front.nodes.BinaryExpNode; 5 | 6 | import java.util.HashMap; 7 | import java.util.HashSet; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | public class BinaryOperator extends InstructionLinkNode { 12 | public enum Op { 13 | ADD, SUB, MULT, DIV, MOD, EQL, GEQ, GRE, LEQ, LSS, NEQ 14 | } 15 | 16 | private static final Map OP_2_OP = new HashMap() { 17 | { 18 | put(BinaryExpNode.BinaryOp.ADD, Op.ADD); 19 | put(BinaryExpNode.BinaryOp.SUB, Op.SUB); 20 | put(BinaryExpNode.BinaryOp.MUL, Op.MULT); 21 | put(BinaryExpNode.BinaryOp.DIV, Op.DIV); 22 | put(BinaryExpNode.BinaryOp.MOD, Op.MOD); 23 | put(BinaryExpNode.BinaryOp.EQL, Op.EQL); 24 | put(BinaryExpNode.BinaryOp.GEQ, Op.GEQ); 25 | put(BinaryExpNode.BinaryOp.GRE, Op.GRE); 26 | put(BinaryExpNode.BinaryOp.LEQ, Op.LEQ); 27 | put(BinaryExpNode.BinaryOp.LSS, Op.LSS); 28 | put(BinaryExpNode.BinaryOp.NEQ, Op.NEQ); 29 | } 30 | }; 31 | 32 | private static final Map OP_TO_IR = new HashMap() { 33 | { 34 | put(Op.ADD, "add"); 35 | put(Op.SUB, "sub"); 36 | put(Op.MULT, "mul"); 37 | put(Op.DIV, "sdiv"); 38 | put(Op.MOD, "srem"); 39 | put(Op.EQL, "eq"); 40 | put(Op.NEQ, "ne"); 41 | put(Op.GRE, "sgt"); 42 | put(Op.GEQ, "sge"); 43 | put(Op.LEQ, "sle"); 44 | put(Op.LSS, "slt"); 45 | } 46 | }; 47 | 48 | private final Op op; 49 | private final TableEntry dst; 50 | private final Operand src1; 51 | private final Operand src2; 52 | 53 | public BinaryOperator(Op op, TableEntry dst, Operand src1, Operand src2) { 54 | super(); 55 | this.op = op; 56 | this.dst = dst; 57 | this.src1 = src1; 58 | this.src2 = src2; 59 | } 60 | 61 | public BinaryOperator(BinaryExpNode.BinaryOp binaryOp, TableEntry dst, Operand src1, Operand src2) { 62 | super(); 63 | this.op = OP_2_OP.get(binaryOp); 64 | this.dst = dst; 65 | this.src1 = src1; 66 | this.src2 = src2; 67 | } 68 | 69 | 70 | public Op getOp() { 71 | return op; 72 | } 73 | 74 | public Operand getSrc1() { 75 | return src1; 76 | } 77 | 78 | public Operand getSrc2() { 79 | return src2; 80 | } 81 | 82 | public TableEntry getDst() { 83 | return dst; 84 | } 85 | 86 | public String toIr() { 87 | switch (op) { 88 | case ADD: 89 | case SUB: 90 | case MULT: 91 | case DIV: 92 | case MOD: 93 | return "\t" + dst.toNameIr() + " = " + OP_TO_IR.get(op) + " " 94 | + TableEntry.TO_IR.get(dst.valueType) + " " + 95 | src1.toNameIr() + ", " + 96 | src2.toNameIr(); 97 | case NEQ: 98 | case LSS: 99 | case LEQ: 100 | case GRE: 101 | case GEQ: 102 | case EQL: 103 | return "\t" + dst.toNameIr() + " = icmp " + OP_TO_IR.get(op) + " " 104 | + TableEntry.TO_IR.get(dst.valueType) + " " + 105 | src1.toNameIr() + ", " + 106 | src2.toNameIr(); 107 | } 108 | return "\t" + dst.toNameIr() + " = " + OP_TO_IR.get(op) + " " 109 | + TableEntry.TO_IR.get(dst.valueType) + " " + 110 | src1.toNameIr() + ", " + 111 | src2.toNameIr(); 112 | 113 | } 114 | 115 | @Override 116 | public TableEntry getDefineVar() { 117 | return this.dst; 118 | } 119 | 120 | @Override 121 | public Set getUseVar() { 122 | Set useSet = new HashSet<>(); 123 | if (src1 instanceof TableEntry) { 124 | useSet.add((TableEntry) src1); 125 | } 126 | if (src2 instanceof TableEntry) { 127 | useSet.add((TableEntry) src2); 128 | } 129 | return useSet; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/mid/ircode/Branch.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | public class Branch extends InstructionLinkNode { 9 | private final Operand cond; 10 | private String labelTrue; 11 | private String labelFalse; 12 | private final BrOp brOp; 13 | 14 | /** 15 | * BEQ: Jump when cond == 0, means jump when cond false, target: labelFalse 16 | * BNE: Jump when cond != 0, means jump when cond true, target: labelTrue 17 | */ 18 | public enum BrOp { 19 | BEQ, BNE 20 | } 21 | 22 | public Branch(Operand cond, String labelTrue, String labelFalse, BrOp brOp) { 23 | super(); 24 | this.cond = cond; 25 | this.labelFalse = labelFalse; 26 | this.labelTrue = labelTrue; 27 | this.brOp = brOp; 28 | } 29 | 30 | public Operand getCond() { 31 | return cond; 32 | } 33 | 34 | public String getLabelFalse() { 35 | return labelFalse; 36 | } 37 | 38 | public String getLabelTrue() { 39 | return labelTrue; 40 | } 41 | 42 | public BrOp getBrOp() { 43 | return brOp; 44 | } 45 | 46 | public String toIr() { 47 | return "\tbr " + cond.toNameIr() + " label %" + labelTrue + " label %" + labelFalse; 48 | } 49 | 50 | public void replaceTarget(String old, String newTarget) { 51 | if (labelTrue.equals(old)) { 52 | labelTrue = newTarget; 53 | } 54 | if (labelFalse.equals(old)) { 55 | labelFalse = newTarget; 56 | } 57 | } 58 | 59 | @Override 60 | public Set getUseVar() { 61 | Set useSet = new HashSet<>(); 62 | if (cond instanceof TableEntry) { 63 | useSet.add((TableEntry) cond); 64 | } 65 | return useSet; 66 | } 67 | 68 | @Override 69 | public TableEntry getDefineVar() { 70 | return null; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/mid/ircode/Call.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.FuncEntry; 4 | import front.TableEntry; 5 | 6 | import java.util.HashSet; 7 | import java.util.List; 8 | import java.util.Set; 9 | import java.util.StringJoiner; 10 | 11 | public class Call extends InstructionLinkNode { 12 | private final FuncEntry funcEntry; 13 | private List args; 14 | private final TableEntry returnDst; 15 | 16 | public Call(FuncEntry funcEntry, List args, TableEntry returnDst) { 17 | super(); 18 | this.funcEntry = funcEntry; 19 | this.args = args; 20 | this.returnDst = returnDst; 21 | } 22 | 23 | public Call(FuncEntry funcEntry, List args) { 24 | super(); 25 | this.funcEntry = funcEntry; 26 | this.args = args; 27 | this.returnDst = null; 28 | } 29 | 30 | public FuncEntry getFuncEntry() { 31 | return funcEntry; 32 | } 33 | 34 | public List getArgs() { 35 | return args; 36 | } 37 | 38 | public TableEntry getReturnDst() { 39 | return returnDst; 40 | } 41 | 42 | @Override 43 | public String toIr() { 44 | StringBuilder sb = new StringBuilder(); 45 | if (returnDst != null) { 46 | sb.append("\t").append(returnDst.toNameIr()).append(" = call "); 47 | } else { 48 | sb.append("\t" + "call "); 49 | } 50 | 51 | sb.append(TableEntry.TO_IR.get(funcEntry.returnType())); 52 | sb.append(" "); 53 | sb.append("@").append(funcEntry.name()).append("("); 54 | StringJoiner sj = new StringJoiner(","); 55 | for (Operand operand : args) { 56 | sj.add(operand.toParamIr()); 57 | } 58 | sb.append(sj); 59 | sb.append(")"); 60 | return sb.toString(); 61 | } 62 | 63 | public void setArgs(List args) { 64 | this.args = args; 65 | } 66 | 67 | @Override 68 | public TableEntry getDefineVar() { 69 | return returnDst; 70 | } 71 | 72 | @Override 73 | public Set getUseVar() { 74 | Set useSet = new HashSet<>(); 75 | for (Operand operand : args) { 76 | if (operand instanceof TableEntry) { 77 | useSet.add((TableEntry) operand); 78 | } 79 | } 80 | return useSet; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/mid/ircode/ElementPtr.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | 5 | import java.util.*; 6 | 7 | public class ElementPtr extends InstructionLinkNode { 8 | private final TableEntry dst; 9 | private final TableEntry.RefType refType; 10 | private final TableEntry.ValueType valueType; 11 | private final TableEntry baseVar; 12 | private final List index = new ArrayList<>(); 13 | 14 | public ElementPtr(TableEntry dst, TableEntry baseVar, List index) { 15 | super(); 16 | this.dst = dst; 17 | this.baseVar = baseVar; 18 | this.refType = baseVar.refType; 19 | this.valueType = baseVar.valueType; 20 | this.index.addAll(index); 21 | } 22 | 23 | @Override 24 | public String toIr() { 25 | StringJoiner sj = new StringJoiner(", "); 26 | for (Operand operand : index) { 27 | if (operand instanceof Immediate) { 28 | sj.add("i32 " + ((Immediate) operand).getValue()); 29 | } else { 30 | sj.add("i32 " + operand.toNameIr()); 31 | } 32 | } 33 | return "\t" + dst.toNameIr() + " = getelementptr " + baseVar.typeToIr() + ", " 34 | + baseVar.typeToIr() + "* " 35 | + baseVar.toNameIr() + ", " + sj; 36 | } 37 | 38 | public TableEntry getDst() { 39 | return dst; 40 | } 41 | 42 | public TableEntry getBaseVar() { 43 | return baseVar; 44 | } 45 | 46 | public List getIndex() { 47 | return index; 48 | } 49 | 50 | @Override 51 | public TableEntry getDefineVar() { 52 | return dst; 53 | } 54 | 55 | @Override 56 | public Set getUseVar() { 57 | Set useSet = new HashSet<>(); 58 | for (Operand operand : index) { 59 | if (operand instanceof TableEntry) { 60 | useSet.add((TableEntry) operand); 61 | } 62 | } 63 | return useSet; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/mid/ircode/FuncDef.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import back.hardware.Memory; 4 | import front.FuncEntry; 5 | import front.SymbolTable; 6 | import front.TableEntry; 7 | import mid.optimize.ColorResult; 8 | import mid.optimize.LiveVariableTable; 9 | import mid.optimize.ReachingDefTable; 10 | 11 | import java.util.*; 12 | 13 | public class FuncDef extends InstructionLinkNode { 14 | private final FuncEntry funcEntry; 15 | private final Map id2Block = new HashMap<>(); 16 | private final Map label2Block = new HashMap<>(); 17 | private final List basicBlocks = new ArrayList<>(); 18 | private final HashSet allLocalVars = new HashSet<>(); 19 | private Integer space = null; 20 | private BasicBlock exitBlock; 21 | private ReachingDefTable reachingDefTable; 22 | private LiveVariableTable liveVariableTable; 23 | private ColorResult colorResult; 24 | 25 | public void setColorResult(ColorResult colorResult) { 26 | this.colorResult = colorResult; 27 | } 28 | 29 | public ColorResult getColorResult() { 30 | return colorResult; 31 | } 32 | 33 | public void setLiveVariableTable(LiveVariableTable liveVariableTable) { 34 | this.liveVariableTable = liveVariableTable; 35 | } 36 | 37 | public LiveVariableTable getLiveVariableTable() { 38 | return liveVariableTable; 39 | } 40 | 41 | public void setExitBlock(BasicBlock exitBlock) { 42 | basicBlocks.add(exitBlock); 43 | this.exitBlock = exitBlock; 44 | label2Block.put(exitBlock.getLabel(), exitBlock); 45 | } 46 | 47 | public BasicBlock getExitBlock() { 48 | return exitBlock; 49 | } 50 | 51 | public FuncDef(FuncEntry funcEntry) { 52 | this.funcEntry = funcEntry; 53 | for (TableEntry tableEntry : funcEntry.args()) { 54 | tableEntry.setDefined(true); 55 | } 56 | } 57 | 58 | public void addBlock(BasicBlock basicBlock) { 59 | basicBlocks.add(basicBlock); 60 | } 61 | 62 | public FuncEntry getFuncEntry() { 63 | return funcEntry; 64 | } 65 | 66 | public List getBasicBlocks() { 67 | return basicBlocks; 68 | } 69 | 70 | public String toIr() { 71 | StringJoiner sj = new StringJoiner("\n"); 72 | sj.add(funcEntry.toIr() + " {"); 73 | for (BasicBlock basicBlock : basicBlocks) { 74 | sj.add(basicBlock.toIr()); 75 | } 76 | sj.add("}"); 77 | return sj.toString(); 78 | } 79 | 80 | public HashSet getAllVars() { 81 | return allLocalVars; 82 | } 83 | 84 | public void addLocalVar(SymbolTable symbolTable) { 85 | allLocalVars.addAll(symbolTable.getVarSymbols().values()); 86 | } 87 | 88 | public int calculateStackSpace() { 89 | if (space == null) { 90 | space = 0; 91 | HashSet allocatedVars = new HashSet<>(); 92 | for (TableEntry tableEntry : funcEntry.args()) { 93 | space += tableEntry.sizeof(); 94 | space = Memory.roundUp(space, 4); 95 | tableEntry.setAddress(Memory.roundDown(space - 1, 4)); 96 | allocatedVars.add(tableEntry); 97 | } 98 | for (TableEntry tableEntry : allLocalVars) { 99 | if (!allocatedVars.contains(tableEntry)) { 100 | space = Memory.roundUp(space, 4); 101 | space += tableEntry.sizeof(); 102 | tableEntry.setAddress(Memory.roundDown(space - 1, 4)); 103 | } 104 | } 105 | space = Memory.roundUp(space, 4); 106 | } 107 | return space; 108 | } 109 | 110 | public Map getId2Block() { 111 | return id2Block; 112 | } 113 | 114 | public Map getLabel2Block() { 115 | return label2Block; 116 | } 117 | 118 | 119 | public void setReachingDefTable(ReachingDefTable reachingDefTable) { 120 | this.reachingDefTable = reachingDefTable; 121 | } 122 | 123 | public ReachingDefTable getReachingDefTable() { 124 | return reachingDefTable; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/mid/ircode/Immediate.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | public class Immediate implements Operand { 4 | private final int value; 5 | 6 | public Immediate(int value) { 7 | this.value = value; 8 | } 9 | 10 | public int getValue() { 11 | return value; 12 | } 13 | 14 | @Override 15 | public String toNameIr() { 16 | return String.valueOf(value); 17 | } 18 | 19 | @Override 20 | public String toParamIr() { 21 | return "i32 " + value; 22 | } 23 | 24 | @Override 25 | public String typeToIr() { 26 | return "i32"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/mid/ircode/Input.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | public class Input extends InstructionLinkNode { 9 | private final TableEntry dst; 10 | 11 | public Input(TableEntry dst) { 12 | super(); 13 | this.dst = dst; 14 | } 15 | 16 | @Override 17 | public TableEntry getDefineVar() { 18 | return dst; 19 | } 20 | 21 | @Override 22 | public Set getUseVar() { 23 | return new HashSet<>(); 24 | } 25 | 26 | public TableEntry getDst() { 27 | return dst; 28 | } 29 | 30 | @Override 31 | public String toIr() { 32 | return "\t" + dst.toNameIr() + " = call i32 @getint()"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/mid/ircode/InstructionLinkNode.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | public class InstructionLinkNode extends User { 9 | private InstructionLinkNode prev = null; 10 | private InstructionLinkNode next = null; 11 | private final int instrId; 12 | private static int ID_COUNTER = 0; 13 | 14 | public InstructionLinkNode() { 15 | this.instrId = ID_COUNTER; 16 | ID_COUNTER += 1; 17 | } 18 | 19 | public int getId() { 20 | return instrId; 21 | } 22 | 23 | public InstructionLinkNode next() { 24 | return next; 25 | } 26 | 27 | public InstructionLinkNode prev() { 28 | return prev; 29 | } 30 | 31 | public void setNext(InstructionLinkNode next) { 32 | this.next = next; 33 | } 34 | 35 | public void setPrev(InstructionLinkNode prev) { 36 | this.prev = prev; 37 | } 38 | 39 | public boolean hasPrev() { 40 | return this.prev == null; 41 | } 42 | 43 | public boolean hasNext() { 44 | return this.next != null; 45 | } 46 | 47 | public void remove() { 48 | if (hasPrev()) { 49 | this.prev.setNext(this.next); 50 | } 51 | 52 | if (hasNext()) { 53 | this.next.setPrev(this.prev); 54 | } 55 | } 56 | 57 | public void insertBefore(InstructionLinkNode irLinkNode) { 58 | irLinkNode.setNext(this); 59 | irLinkNode.setPrev(this.prev); 60 | if (hasPrev()) { 61 | this.prev.setNext(irLinkNode); 62 | } 63 | this.prev = irLinkNode; 64 | } 65 | 66 | public void insertAfter(InstructionLinkNode irLinkNode) { 67 | irLinkNode.setPrev(this); 68 | irLinkNode.setNext(this.next); 69 | if (hasNext()) { 70 | this.next.setPrev(irLinkNode); 71 | } 72 | this.next = irLinkNode; 73 | } 74 | 75 | public void append(InstructionLinkNode irLinkNode) { 76 | InstructionLinkNode ptr = this; 77 | while (ptr.hasNext()) { 78 | ptr = ptr.next(); 79 | } 80 | ptr.setNext(irLinkNode); 81 | irLinkNode.setPrev(ptr); 82 | } 83 | 84 | public Set getUseVar() { 85 | return new HashSet<>(); 86 | } 87 | 88 | public TableEntry getDefineVar() { 89 | return null; 90 | } 91 | 92 | public String toIr() { 93 | return null; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/mid/ircode/Jump.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | public class Jump extends InstructionLinkNode { 4 | private String target; 5 | 6 | public Jump(String target) { 7 | super(); 8 | this.target = target; 9 | } 10 | 11 | public String getTarget() { 12 | return target; 13 | } 14 | 15 | public String toIr() { 16 | return "\tbr label %" + target; 17 | } 18 | 19 | public void setTarget(String target) { 20 | this.target = target; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/mid/ircode/Operand.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | public interface Operand { 4 | String toNameIr(); 5 | String toParamIr(); 6 | String typeToIr(); 7 | } 8 | -------------------------------------------------------------------------------- /src/mid/ircode/PointerOp.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | public class PointerOp extends InstructionLinkNode { 9 | public enum Op { 10 | LOAD, STORE 11 | } 12 | 13 | private final Op op; 14 | private final Operand src; 15 | private final TableEntry dst; 16 | 17 | public PointerOp(Op op, TableEntry dst, Operand src) { 18 | super(); 19 | this.op = op; 20 | this.src = src; 21 | this.dst = dst; 22 | } 23 | 24 | @Override 25 | public String toIr() { 26 | if (this.op == Op.LOAD) { 27 | return "\t" + dst.toNameIr() + " = load " + 28 | dst.typeToIr() + ", " + 29 | src.typeToIr() + "* " + src.toNameIr(); 30 | } else { 31 | return "\t" + "store " + dst.typeToIr() + " " + src.toNameIr() + ", " 32 | + dst.typeToIr() + "* " + dst.toNameIr(); 33 | } 34 | } 35 | 36 | public TableEntry getDst() { 37 | return dst; 38 | } 39 | 40 | public Operand getSrc() { 41 | return src; 42 | } 43 | 44 | public Op getOp() { 45 | return op; 46 | } 47 | 48 | @Override 49 | public TableEntry getDefineVar() { 50 | if (op == Op.LOAD) { 51 | return dst; 52 | } else { 53 | if (dst.refType == TableEntry.RefType.ITEM) { 54 | return dst; 55 | } 56 | } 57 | return null; 58 | } 59 | 60 | @Override 61 | public Set getUseVar() { 62 | Set useSet = new HashSet<>(); 63 | if (src instanceof TableEntry) { 64 | useSet.add((TableEntry) src); 65 | } 66 | if (op == Op.STORE && dst.refType == TableEntry.RefType.POINTER) { 67 | useSet.add(dst); 68 | } 69 | return useSet; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/mid/ircode/PrintInt.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | public class PrintInt extends InstructionLinkNode { 9 | private final Operand value; 10 | 11 | public PrintInt(Operand value) { 12 | super(); 13 | this.value = value; 14 | } 15 | 16 | public Operand getValue() { 17 | return value; 18 | } 19 | 20 | @Override 21 | public String toIr() { 22 | return "\t" + "call void @putint(" + 23 | ((value instanceof Immediate) ? "i32" : 24 | TableEntry.TO_IR.get(((TableEntry) value).valueType)) 25 | + " " + value.toNameIr() + " )"; 26 | } 27 | 28 | @Override 29 | public Set getUseVar() { 30 | Set useSet = new HashSet<>(); 31 | if (value instanceof TableEntry) { 32 | useSet.add((TableEntry) value); 33 | } 34 | return useSet; 35 | } 36 | 37 | @Override 38 | public TableEntry getDefineVar() { 39 | return super.getDefineVar(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/mid/ircode/PrintStr.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | 5 | import java.util.Set; 6 | import java.util.StringJoiner; 7 | 8 | public class PrintStr extends InstructionLinkNode { 9 | private final String label; 10 | private final String content; 11 | private final boolean singleChar = true; 12 | 13 | public PrintStr(String label, String content) { 14 | super(); 15 | this.label = label; 16 | this.content = content.replace("\\" + "n", "\n"); 17 | } 18 | 19 | public String getLabel() { 20 | return label; 21 | } 22 | 23 | public String getContent() { 24 | return content; 25 | } 26 | 27 | @Override 28 | public String toIr() { 29 | if (singleChar) { 30 | StringJoiner sj = new StringJoiner("\n"); 31 | for (int i = 0; i < content.length(); i++) { 32 | sj.add("\t" + "call void @putch(i32 " + (int) content.charAt(i) + " ) " + 33 | "; '" + (content.charAt(i) == '\n' ? "\\n" : content.charAt(i)) + "'"); 34 | } 35 | return sj.toString(); 36 | } else { 37 | //TODO 38 | return null; 39 | } 40 | } 41 | 42 | @Override 43 | public Set getUseVar() { 44 | return super.getUseVar(); 45 | } 46 | 47 | @Override 48 | public TableEntry getDefineVar() { 49 | return super.getDefineVar(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/mid/ircode/Return.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | public class Return extends InstructionLinkNode { 9 | private final Operand returnValue; 10 | 11 | public Return(Operand operand) { 12 | super(); 13 | this.returnValue = operand; 14 | } 15 | 16 | public Operand getReturnValue() { 17 | return returnValue; 18 | } 19 | 20 | @Override 21 | public String toIr() { 22 | if (returnValue != null) { 23 | return "\tret " + ((returnValue instanceof Immediate) ? "i32" : 24 | TableEntry.TO_IR.get(((TableEntry) returnValue).valueType)) 25 | + " " + returnValue.toNameIr(); 26 | } else { 27 | return "\t ret void"; 28 | } 29 | } 30 | 31 | @Override 32 | public Set getUseVar() { 33 | Set useSet = new HashSet<>(); 34 | if (returnValue != null && returnValue instanceof TableEntry) { 35 | useSet.add((TableEntry) returnValue); 36 | } 37 | return useSet; 38 | } 39 | 40 | @Override 41 | public TableEntry getDefineVar() { 42 | return super.getDefineVar(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/mid/ircode/UnaryOperator.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | import front.nodes.UnaryExpNode; 5 | 6 | import java.util.HashMap; 7 | import java.util.HashSet; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | public class UnaryOperator extends InstructionLinkNode { 12 | public enum Op { 13 | PLUS, MINU, NOT 14 | } 15 | 16 | private static final Map OP_TO_IR = new HashMap() { 17 | { 18 | put(Op.PLUS, "add"); 19 | put(Op.MINU, "sub"); 20 | put(Op.NOT, "ne"); 21 | 22 | } 23 | }; 24 | 25 | private static final Map OP_2_OP = new HashMap() { 26 | { 27 | put(UnaryExpNode.UnaryOp.PLUS, Op.PLUS); 28 | put(UnaryExpNode.UnaryOp.MINU, Op.MINU); 29 | put(UnaryExpNode.UnaryOp.NOT, Op.NOT); 30 | } 31 | }; 32 | 33 | private final Op op; 34 | private final TableEntry dst; 35 | private final Operand src; 36 | 37 | public UnaryOperator(UnaryExpNode.UnaryOp op, TableEntry dst, Operand src) { 38 | super(); 39 | this.op = OP_2_OP.get(op); 40 | this.dst = dst; 41 | this.src = src; 42 | } 43 | 44 | public UnaryOperator(Op op, TableEntry dst, Operand src) { 45 | super(); 46 | this.op = op; 47 | this.dst = dst; 48 | this.src = src; 49 | } 50 | 51 | 52 | public TableEntry getDst() { 53 | return dst; 54 | } 55 | 56 | public Op getOp() { 57 | return op; 58 | } 59 | 60 | public Operand getSrc() { 61 | return src; 62 | } 63 | 64 | public String toIr() { 65 | switch (op) { 66 | case PLUS: 67 | case MINU: 68 | return "\t" + dst.toNameIr() + " = " + OP_TO_IR.get(op) + " " 69 | + TableEntry.TO_IR.get(dst.valueType) + " " + 70 | "0, " + 71 | src.toNameIr(); 72 | case NOT: 73 | return "\t" + dst.toNameIr() + " = icmp " + OP_TO_IR.get(op) + " " 74 | + TableEntry.TO_IR.get(dst.valueType) + " " + 75 | "0, " + 76 | src.toNameIr(); 77 | 78 | } 79 | return "\t" + dst.toNameIr() + " = " + OP_TO_IR.get(op) + " " 80 | + TableEntry.TO_IR.get(dst.valueType) + " " + 81 | "0, " + 82 | src.toNameIr(); 83 | } 84 | 85 | @Override 86 | public Set getUseVar() { 87 | Set useSet = new HashSet<>(); 88 | if (src instanceof TableEntry) { 89 | useSet.add((TableEntry) src); 90 | } 91 | return useSet; 92 | } 93 | 94 | @Override 95 | public TableEntry getDefineVar() { 96 | return dst; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/mid/ircode/User.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | public abstract class User extends Value{ 4 | } 5 | -------------------------------------------------------------------------------- /src/mid/ircode/Value.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | public abstract class Value { 4 | } 5 | -------------------------------------------------------------------------------- /src/mid/ircode/VarDef.java: -------------------------------------------------------------------------------- 1 | package mid.ircode; 2 | 3 | import front.TableEntry; 4 | 5 | public class VarDef extends InstructionLinkNode { 6 | private final TableEntry tableEntry; 7 | 8 | public VarDef(TableEntry tableEntry) { 9 | this.tableEntry = tableEntry; 10 | } 11 | 12 | public TableEntry getTableEntry() { 13 | return tableEntry; 14 | } 15 | 16 | @Override 17 | public String toIr() { 18 | return "\t" + tableEntry.toNameIr() + " = alloca " + tableEntry.typeToIr(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/mid/optimize/ColorResult.java: -------------------------------------------------------------------------------- 1 | package mid.optimize; 2 | 3 | import front.TableEntry; 4 | 5 | import java.util.*; 6 | import java.util.stream.Collectors; 7 | 8 | public class ColorResult { 9 | private final Map> allocMap = new HashMap<>(); 10 | private static final Set availableReg = new LinkedHashSet() { 11 | { 12 | add(16); 13 | add(17); 14 | add(18); 15 | add(19); 16 | add(20); 17 | add(21); 18 | add(22); 19 | add(23); 20 | } 21 | }; 22 | private final Map var2Reg = new HashMap<>(); 23 | 24 | public ColorResult() { 25 | for (Integer i : availableReg) { 26 | allocMap.put(i, new HashSet<>()); 27 | } 28 | } 29 | 30 | public void allocVar(TableEntry tableEntry, Set conflict) { 31 | Set conflictSet = conflict.stream() 32 | .map(tableEntry1 -> var2Reg.getOrDefault(tableEntry1, 0)) 33 | .collect(Collectors.toSet()); 34 | Set available = Util.sub(availableReg, conflictSet); 35 | if (available.size() > 0) { 36 | int reg = available.iterator().next(); 37 | allocMap.get(reg).add(tableEntry); 38 | var2Reg.put(tableEntry, reg); 39 | } 40 | } 41 | 42 | public static Set getAvailableReg() { 43 | return availableReg; 44 | } 45 | 46 | public Map getVar2Reg() { 47 | return var2Reg; 48 | } 49 | 50 | public Map> getAllocMap() { 51 | return allocMap; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | StringJoiner sj = new StringJoiner("\n"); 57 | for (int reg : availableReg) { 58 | StringJoiner sj2 = new StringJoiner(", "); 59 | for (TableEntry tableEntry : allocMap.get(reg)) { 60 | sj2.add(tableEntry.toNameIr()); 61 | } 62 | sj.add(reg + ":" + sj2); 63 | } 64 | return sj.toString(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/mid/optimize/IrOptimizer.java: -------------------------------------------------------------------------------- 1 | package mid.optimize; 2 | 3 | import mid.IrModule; 4 | 5 | public class IrOptimizer { 6 | public static IrModule optimize(IrModule irModule) { 7 | irModule = FlowGraphBuilder.buildFlowGraph(irModule); 8 | irModule = FlowGraphBuilder.removeEmptyBlock(irModule); 9 | irModule = FlowGraphBuilder.mergeBlock(irModule); 10 | irModule = Peephole.optimize(irModule); 11 | irModule = ConstantPropagation.constPro(irModule); 12 | irModule = DeadCodeKiller.deadCodeInBasicBlock(irModule); 13 | irModule = DeadCodeKiller.killUnreachableBlock(irModule); 14 | irModule = CopyPropagation.copyPropagation(irModule); 15 | irModule = DeadCodeKiller.deadCodeInBasicBlock(irModule); 16 | irModule = ColorScheduler.colorScheduleReg(irModule); 17 | return irModule; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/mid/optimize/LiveVariableAnalyser.java: -------------------------------------------------------------------------------- 1 | package mid.optimize; 2 | 3 | import mid.IrModule; 4 | import mid.ircode.BasicBlock; 5 | import mid.ircode.FuncDef; 6 | 7 | public class LiveVariableAnalyser { 8 | public static IrModule reachingDefAnalysis(IrModule irModule) { 9 | for (FuncDef funcDef : irModule.getFuncDefs()) { 10 | liveVariableAnalyseFunc(funcDef); 11 | } 12 | return irModule; 13 | } 14 | 15 | public static void liveVariableAnalyseFunc(FuncDef funcDef) { 16 | LiveVariableTable liveVariableTable = new LiveVariableTable(); 17 | for (BasicBlock basicBlock : funcDef.getBasicBlocks()) { 18 | liveVariableTable.calculateDefUse(basicBlock); 19 | } 20 | liveVariableTable.calculateInOut(funcDef.getBasicBlocks()); 21 | funcDef.setLiveVariableTable(liveVariableTable); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/mid/optimize/LiveVariableTable.java: -------------------------------------------------------------------------------- 1 | package mid.optimize; 2 | 3 | import front.TableEntry; 4 | import mid.ircode.BasicBlock; 5 | import mid.ircode.InstructionLinkNode; 6 | 7 | import java.util.*; 8 | 9 | public class LiveVariableTable { 10 | private final Map> in = new HashMap<>(); 11 | private final Map> out = new HashMap<>(); 12 | private final Map> def = new HashMap<>(); 13 | private final Map> use = new HashMap<>(); 14 | 15 | public LiveVariableTable(){ 16 | 17 | } 18 | 19 | public Map> getDef() { 20 | return def; 21 | } 22 | 23 | public Map> getIn() { 24 | return in; 25 | } 26 | 27 | public Map> getOut() { 28 | return out; 29 | } 30 | 31 | public Map> getUse() { 32 | return use; 33 | } 34 | 35 | public void calculateDefUse(BasicBlock basicBlock) { 36 | in.put(basicBlock.getLabel(), new HashSet<>()); 37 | out.put(basicBlock.getLabel(), new HashSet<>()); 38 | Set useOfBlock = new HashSet<>(); 39 | Set defOfBlock = new HashSet<>(); 40 | InstructionLinkNode instr = basicBlock.getFirstInstruction(); 41 | while (!instr.equals(basicBlock.getEnd())) { 42 | Set useVar = instr.getUseVar(); 43 | for (TableEntry tableEntry : useVar) { 44 | if (!tableEntry.isTemp && !tableEntry.isGlobal) { 45 | if (!defOfBlock.contains(tableEntry)) { 46 | useOfBlock.add(tableEntry); 47 | } 48 | } 49 | } 50 | TableEntry defVar = instr.getDefineVar(); 51 | if (defVar != null) { 52 | if (!defVar.isGlobal && !defVar.isTemp) { 53 | if (!useOfBlock.contains(defVar)) { 54 | defOfBlock.add(defVar); 55 | } 56 | } 57 | } 58 | instr = instr.next(); 59 | } 60 | def.put(basicBlock.getLabel(), defOfBlock); 61 | use.put(basicBlock.getLabel(), useOfBlock); 62 | } 63 | 64 | public void calculateInOut(List basicBlocks) { 65 | boolean change; 66 | do { 67 | change = false; 68 | for (int i = basicBlocks.size() - 1; i >= 0; i--) { 69 | BasicBlock basicBlock = basicBlocks.get(i); 70 | Set newOut = new HashSet<>(); 71 | for (String nextLabel : basicBlock.getNextBlock()) { 72 | newOut = Util.cup(newOut, in.getOrDefault(nextLabel, new HashSet<>())); 73 | } 74 | Set newIn = Util.cup(use.get(basicBlock.getLabel()), Util.sub(newOut, def.get(basicBlock.getLabel()))); 75 | if (!in.get(basicBlock.getLabel()).equals(newIn) || !out.get(basicBlock.getLabel()).equals(newOut)) { 76 | change = true; 77 | } 78 | in.put(basicBlock.getLabel(), newIn); 79 | out.put(basicBlock.getLabel(), newOut); 80 | } 81 | } while (change); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/mid/optimize/Peephole.java: -------------------------------------------------------------------------------- 1 | package mid.optimize; 2 | 3 | import front.TableEntry; 4 | import mid.IrModule; 5 | import mid.ircode.*; 6 | 7 | public class Peephole { 8 | public static IrModule optimize(IrModule irModule) { 9 | for (FuncDef funcDef : irModule.getFuncDefs()) { 10 | for (BasicBlock basicBlock : funcDef.getBasicBlocks()) { 11 | InstructionLinkNode inst = basicBlock.next(); 12 | while (!inst.equals(basicBlock.getEnd())) { 13 | if (inst instanceof BinaryOperator) { 14 | if (((BinaryOperator) inst).getOp() == BinaryOperator.Op.MULT) { 15 | Util.replaceInstr(inst, simpleMult((BinaryOperator) inst)); 16 | } else if (((BinaryOperator) inst).getOp() == BinaryOperator.Op.DIV) { 17 | Util.replaceInstr(inst, simpleDiv((BinaryOperator) inst)); 18 | } else if (((BinaryOperator) inst).getOp() == BinaryOperator.Op.MOD) { 19 | Util.replaceInstr(inst, simpleMod((BinaryOperator) inst)); 20 | } 21 | } 22 | if (inst instanceof PointerOp && 23 | ((PointerOp) inst).getOp() == PointerOp.Op.LOAD) { 24 | if (inst.next() instanceof PointerOp && 25 | ((PointerOp) inst.next()).getOp() == PointerOp.Op.STORE) { 26 | if (((PointerOp) inst).getSrc() == ((PointerOp) inst.next()).getDst()) { 27 | Util.removeInstr(inst); 28 | inst = inst.next(); 29 | Util.removeInstr(inst); 30 | } 31 | } 32 | } 33 | inst = inst.next(); 34 | } 35 | } 36 | } 37 | return irModule; 38 | } 39 | 40 | public static InstructionLinkNode simpleMult(BinaryOperator instr) { 41 | if (eqZero(instr.getSrc1()) || eqZero(instr.getSrc2())) { 42 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), new Immediate(0)); 43 | } else if (eqOne(instr.getSrc1()) && eqOne(instr.getSrc2()) || 44 | eqNegOne(instr.getSrc1()) && eqNegOne(instr.getSrc2())) { 45 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), new Immediate(1)); 46 | } else if (eqOne(instr.getSrc1())) { 47 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), instr.getSrc2()); 48 | } else if (eqNegOne(instr.getSrc1())) { 49 | return new UnaryOperator(UnaryOperator.Op.MINU, instr.getDst(), instr.getSrc2()); 50 | } else if (eqOne(instr.getSrc2())) { 51 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), instr.getSrc1()); 52 | } else if (eqNegOne(instr.getSrc2())) { 53 | return new UnaryOperator(UnaryOperator.Op.MINU, instr.getDst(), instr.getSrc1()); 54 | } 55 | return instr; 56 | } 57 | 58 | public static InstructionLinkNode simpleDiv(BinaryOperator instr) { 59 | if (eqZero(instr.getSrc1())) { 60 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), new Immediate(0)); 61 | } else if (eqOne(instr.getSrc1()) && eqOne(instr.getSrc2()) || 62 | eqNegOne(instr.getSrc1()) && eqNegOne(instr.getSrc2())) { 63 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), new Immediate(1)); 64 | } else if (eqOne(instr.getSrc2())) { 65 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), instr.getSrc1()); 66 | } else if (eqNegOne(instr.getSrc2())) { 67 | return new UnaryOperator(UnaryOperator.Op.MINU, instr.getDst(), instr.getSrc1()); 68 | } 69 | return instr; 70 | } 71 | 72 | public static InstructionLinkNode simpleMod(BinaryOperator instr) { 73 | if (eqZero(instr.getSrc1()) || eqZero(instr.getSrc2())) { 74 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), new Immediate(0)); 75 | } else if (eqOne(instr.getSrc1()) && eqOne(instr.getSrc2()) || 76 | eqNegOne(instr.getSrc1()) && eqNegOne(instr.getSrc2())) { 77 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), new Immediate(0)); 78 | } else if (eqOne(instr.getSrc2())) { 79 | return new UnaryOperator(UnaryOperator.Op.PLUS, instr.getDst(), new Immediate(0)); 80 | } else if (eqNegOne(instr.getSrc2())) { 81 | return new UnaryOperator(UnaryOperator.Op.MINU, instr.getDst(), new Immediate(0)); 82 | } 83 | return instr; 84 | } 85 | 86 | public static boolean eqOne(Operand operand) { 87 | if (operand instanceof TableEntry) { 88 | return false; 89 | } else if (operand instanceof Immediate) { 90 | return ((Immediate) operand).getValue() == 1; 91 | } 92 | return false; 93 | } 94 | 95 | public static boolean eqZero(Operand operand) { 96 | if (operand instanceof TableEntry) { 97 | return false; 98 | } else if (operand instanceof Immediate) { 99 | return ((Immediate) operand).getValue() == 0; 100 | } 101 | return false; 102 | } 103 | 104 | public static boolean eqNegOne(Operand operand) { 105 | if (operand instanceof TableEntry) { 106 | return false; 107 | } else if (operand instanceof Immediate) { 108 | return ((Immediate) operand).getValue() == -1; 109 | } 110 | return false; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/mid/optimize/ReachingDefAnalyser.java: -------------------------------------------------------------------------------- 1 | package mid.optimize; 2 | 3 | import mid.IrModule; 4 | import mid.ircode.BasicBlock; 5 | import mid.ircode.FuncDef; 6 | import mid.ircode.InstructionLinkNode; 7 | 8 | public class ReachingDefAnalyser { 9 | public static IrModule reachingDefAnalysis(IrModule irModule) { 10 | for (FuncDef funcDef : irModule.getFuncDefs()) { 11 | reachingDefAnalyseFunc(funcDef); 12 | } 13 | return irModule; 14 | } 15 | 16 | public static void reachingDefAnalyseFunc(FuncDef funcDef) { 17 | ReachingDefTable reachingDefTable = new ReachingDefTable(); 18 | for (BasicBlock basicBlock : funcDef.getBasicBlocks()) { 19 | signDef(basicBlock, reachingDefTable); 20 | } 21 | for (BasicBlock basicBlock : funcDef.getBasicBlocks()) { 22 | reachingDefTable.calculateGenKill(basicBlock); 23 | } 24 | reachingDefTable.calculateInOut(funcDef.getBasicBlocks()); 25 | funcDef.setReachingDefTable(reachingDefTable); 26 | } 27 | 28 | public static void signDef(BasicBlock basicBlock, ReachingDefTable reachingDefTable) { 29 | InstructionLinkNode ptr = basicBlock.next(); 30 | while (ptr != basicBlock.getEnd()) { 31 | reachingDefTable.signDef(ptr); 32 | ptr = ptr.next(); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/mid/optimize/Util.java: -------------------------------------------------------------------------------- 1 | package mid.optimize; 2 | 3 | import front.TableEntry; 4 | import mid.ircode.InstructionLinkNode; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | 10 | public class Util { 11 | public static Set cap(Set a, Set b) { 12 | HashSet ans = new HashSet<>(a); 13 | ans.retainAll(b); 14 | return ans; 15 | } 16 | 17 | public static Set sub(T a, Set b) { 18 | Set ans = new HashSet<>(); 19 | ans.add(a); 20 | ans.removeAll(b); 21 | return ans; 22 | } 23 | 24 | public static Set sub(Set a, Set b) { 25 | Set ans = new HashSet<>(a); 26 | ans.removeAll(b); 27 | return ans; 28 | } 29 | 30 | public static Set sub(Set a, T b) { 31 | Set ans = new HashSet<>(a); 32 | ans.remove(b); 33 | return ans; 34 | } 35 | 36 | public static Set cup(Set a, Set b) { 37 | Set newSet = new HashSet<>(a); 38 | newSet.addAll(b); 39 | return newSet; 40 | } 41 | 42 | public static Set cup(Set b, T a) { 43 | HashSet ans = new HashSet<>(); 44 | ans.add(a); 45 | ans.addAll(b); 46 | return ans; 47 | } 48 | 49 | public static void replaceInstr(InstructionLinkNode oldInstr, InstructionLinkNode newInstr) { 50 | newInstr.setPrev(oldInstr.prev()); 51 | newInstr.setNext(oldInstr.next()); 52 | oldInstr.prev().setNext(newInstr); 53 | oldInstr.next().setPrev(newInstr); 54 | } 55 | 56 | public static void removeInstr(InstructionLinkNode instr) { 57 | instr.prev().setNext(instr.next()); 58 | instr.next().setPrev(instr.prev()); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/mid/optimize/Value.java: -------------------------------------------------------------------------------- 1 | package mid.optimize; 2 | 3 | import java.util.Objects; 4 | 5 | public class Value { 6 | 7 | enum ValueType { 8 | UNDEF, NAC, CONS; 9 | } 10 | 11 | private final Integer constValue; 12 | private final ValueType valueType; 13 | 14 | public Value(ValueType valueType, Integer constValue) { 15 | this.valueType = valueType; 16 | this.constValue = constValue; 17 | } 18 | 19 | public ValueType valueType() { 20 | return valueType; 21 | } 22 | 23 | public Integer constValue() { 24 | return constValue; 25 | } 26 | 27 | @Override 28 | public boolean equals(Object o) { 29 | if (this == o) return true; 30 | if (o == null || getClass() != o.getClass()) return false; 31 | Value value = (Value) o; 32 | return Objects.equals(constValue, value.constValue) && valueType == value.valueType; 33 | } 34 | 35 | @Override 36 | public int hashCode() { 37 | return Objects.hash(constValue, valueType); 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "valueType=" + valueType + " constValue=" + constValue; 43 | 44 | } 45 | } -------------------------------------------------------------------------------- /src/util/Pair.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | public class Pair { 4 | public static Pair of(S f, V s) { 5 | return new Pair<>(f, s); 6 | } 7 | 8 | public final T o1; 9 | public final U o2; 10 | 11 | public Pair(T o1, U o2) { 12 | this.o1 = o1; 13 | this.o2 = o2; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/test-mips.py: -------------------------------------------------------------------------------- 1 | # -- coding: utf-8 -- 2 | import os 3 | 4 | 5 | def GetProgressBar(count=0, totalCount=1, name=""): 6 | bar = "|" 7 | plusCount = 50 * count // totalCount 8 | for _ in range(plusCount): 9 | bar = bar + ">" 10 | for _ in range(50 - plusCount): 11 | bar = bar + "-" 12 | bar = bar + "|" + str(round(100 * count / totalCount, 2)).rjust(10) + "%" + name.rjust(50) 13 | return bar 14 | 15 | 16 | testFileDir = ".\\full2021" 17 | 18 | jarDir = "..\\out\\artifacts\\SysY_MIPS_Compiler_jar\\SysY-MIPS-Compiler.jar" 19 | 20 | mipsFile = "mips.asm" 21 | 22 | if __name__ == '__main__': 23 | totalDataCount = 0 24 | for dataDirRoot, dataDirDirs, dataDirFiles in os.walk(testFileDir): 25 | for fileName in dataDirFiles: 26 | if (fileName[-4:] == ".txt" and fileName[0:8] == "testfile"): 27 | totalDataCount = totalDataCount + 1 28 | 29 | if totalDataCount == 0: 30 | print("No test data!") 31 | exit() 32 | os.system("copy " + jarDir + " SysY-MIPS-Compiler.jar") 33 | print("total test data count: " + str(totalDataCount)) 34 | print(GetProgressBar(name="testing ...")) 35 | correctCount = 0 36 | count = 0 37 | for dataDirRoot, dataDirDirs, dataDirFiles in os.walk(testFileDir): 38 | for fileName in dataDirFiles: 39 | if (fileName[-4:] == ".txt" and fileName[0:8] == "testfile" ): 40 | inFile = os.path.join(dataDirRoot, fileName) 41 | 42 | 43 | 44 | print(GetProgressBar(count, totalDataCount, inFile)) 45 | 46 | 47 | 48 | os.system("copy " + os.path.join(dataDirRoot, fileName) + " testfile.txt") 49 | os.system("copy " + os.path.join(dataDirRoot, fileName) + " ..\\testfile.txt") 50 | os.system("java -jar SysY-MIPS-Compiler.jar") 51 | os.system("copy mips.txt mips.asm") 52 | os.system("copy mips.txt ..\\mips.txt") 53 | os.system("copy llvm_ir.txt ..\\llvm_ir.txt") 54 | if(os.path.exists("llvm_ir_optimize.txt")): 55 | os.system("copy llvm_ir_optimize.txt ..\\llvm_ir_optimize.txt") 56 | #stdFile = ".\\Syntax-analysis"+ dataDirRoot[16:] 57 | print("Compiled finished, running testfile") 58 | inputFile = fileName.replace("testfile", "input") 59 | std_out_file = fileName.replace("testfile", "output") 60 | os.system("copy " + os.path.join(dataDirRoot, inputFile) + " input.txt") 61 | os.system("copy " + os.path.join(dataDirRoot, inputFile) + " ..\\input.txt") 62 | os.system("copy " + os.path.join(dataDirRoot, std_out_file) + " output.txt") 63 | os.system("copy " + os.path.join(dataDirRoot, std_out_file) + " ..\\output.txt") 64 | 65 | os.system("java -jar mars.jar nc mc Default mips.asm < input.txt > my_output.txt") 66 | 67 | 68 | 69 | if (os.system("fc my_output.txt output.txt")): 70 | print("Wrong Answer in " + os.path.join(dataDirRoot, fileName)) 71 | exit() 72 | 73 | count = count + 1 74 | 75 | print(GetProgressBar(totalDataCount, totalDataCount, "Done.")) 76 | print("Accept.") -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | # -- coding: utf-8 -- 2 | import os 3 | 4 | 5 | def GetProgressBar(count=0, totalCount=1, name=""): 6 | bar = "|" 7 | plusCount = 50 * count // totalCount 8 | for _ in range(plusCount): 9 | bar = bar + ">" 10 | for _ in range(50 - plusCount): 11 | bar = bar + "-" 12 | bar = bar + "|" + str(round(100 * count / totalCount, 2)).rjust(10) + "%" + name.rjust(50) 13 | return bar 14 | 15 | 16 | testFileDir = ".\\testfiles-only" 17 | 18 | jarDir = "..\\out\\artifacts\\SysY_MIPS_Compiler_jar\\SysY-MIPS-Compiler.jar" 19 | 20 | myOutFile = "output.txt" 21 | 22 | if __name__ == '__main__': 23 | totalDataCount = 0 24 | for dataDirRoot, dataDirDirs, dataDirFiles in os.walk(testFileDir): 25 | for fileName in dataDirFiles: 26 | if (fileName[-4:] == ".txt" and fileName[0:8] == "testfile"): 27 | totalDataCount = totalDataCount + 1 28 | 29 | if totalDataCount == 0: 30 | print("No test data!") 31 | exit() 32 | os.system("copy " + jarDir + " SysY-MIPS-Compiler.jar") 33 | print("total test data count: " + str(totalDataCount)) 34 | print(GetProgressBar(name="testing ...")) 35 | correctCount = 0 36 | count = 0 37 | for dataDirRoot, dataDirDirs, dataDirFiles in os.walk(testFileDir): 38 | for fileName in dataDirFiles: 39 | if (fileName[-4:] == ".txt" and fileName[0:8] == "testfile" ): 40 | inFile = os.path.join(dataDirRoot, fileName) 41 | 42 | 43 | 44 | print(GetProgressBar(count, totalDataCount, inFile)) 45 | 46 | 47 | 48 | os.system("copy " + os.path.join(dataDirRoot, fileName) + " testfile.txt") 49 | os.system("java -jar SysY-MIPS-Compiler.jar") 50 | #stdFile = ".\\Syntax-analysis"+ dataDirRoot[16:] 51 | 52 | stdFile = dataDirRoot.replace("testfiles-only","Syntax-analysis") 53 | #stdFile = dataDirRoot 54 | stdFile = os.path.join(stdFile, "output"+fileName[8:]) 55 | ansFile = "ans.txt" 56 | print(stdFile) 57 | os.system("copy "+ stdFile + " " + ansFile) 58 | 59 | if (os.system("fc " + ansFile + " " + myOutFile)): 60 | print("Wrong Answer in " + os.path.join(dataDirRoot, fileName)) 61 | exit() 62 | 63 | count = count + 1 64 | 65 | print(GetProgressBar(totalDataCount, totalDataCount, "Done.")) 66 | print("Accept.") -------------------------------------------------------------------------------- /testfiles/input1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /testfiles/input2.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arthuring/SysY-MIPS-Compiler/efa57a2f0b13c1b13c9076fd232090019b2d270e/testfiles/input2.txt -------------------------------------------------------------------------------- /testfiles/input3.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /testfiles/input4.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /testfiles/input5.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arthuring/SysY-MIPS-Compiler/efa57a2f0b13c1b13c9076fd232090019b2d270e/testfiles/input5.txt -------------------------------------------------------------------------------- /testfiles/output1.txt: -------------------------------------------------------------------------------- 1 | 20373091 2 | 2 4 1 0 3 | 1 1 4 | 1 5 | 4 6 | 9 7 | 16 8 | 25 9 | 9 10 | 10 -------------------------------------------------------------------------------- /testfiles/output2.txt: -------------------------------------------------------------------------------- 1 | 20373091 2 | 101 100 1 3 | 101 4 | 400 5 | 120 6 | :( ) 7 | :) )) 8 | :) ))) 9 | :) )))) 10 | :) ))))) -------------------------------------------------------------------------------- /testfiles/output3.txt: -------------------------------------------------------------------------------- 1 | 20373091 2 | 2 2 1 3 3 | 1 1 4 | 1 5 | 4 6 | 9 7 | 16 8 | 25 9 | 9 10 | 10 -------------------------------------------------------------------------------- /testfiles/output4.txt: -------------------------------------------------------------------------------- 1 | 20373091 2 | 2 4 1 0 3 | 1 1 4 | 1 5 | 4 6 | 9 7 | 16 8 | 25 9 | 9 10 | 10 -------------------------------------------------------------------------------- /testfiles/output5.txt: -------------------------------------------------------------------------------- 1 | 20373091 2 | 101 100 1 3 | 1 4 | 2 5 | 120 6 | :( ) 7 | :) )) 8 | :) ))) 9 | :) )))) 10 | :) ))))) -------------------------------------------------------------------------------- /testfiles/testfile1.txt: -------------------------------------------------------------------------------- 1 | /* A1 2 | * Decl x FuncDef x 3 | * Exp * Stmt * 4 | * Func x 5 | */ 6 | int main(){ 7 | printf("20373091\n"); 8 | const int a=1; 9 | const int b=2, c=3, d=a+b; //genearal TODO 10 | int var1; 11 | int _var2 = ((((a+1) * (b-1))/4)%1)+1+c , _var3, _var4; 12 | int correct=1, uncorrect=0; 13 | var1=correct+1; 14 | _var3=getint(); 15 | _var4=0; 16 | int cnt=0; 17 | printf("%d %d %d %d\n",var1,_var2,_var3,_var4); 18 | 19 | if(correct > uncorrect){ 20 | ; 21 | uncorrect+1; 22 | uncorrect=uncorrect+1; 23 | } 24 | if(correct != uncorrect){ 25 | if(correct == uncorrect){ 26 | uncorrect=uncorrect+1; 27 | } 28 | }else{ 29 | printf("%d %d\n",correct,uncorrect); 30 | } 31 | 32 | while(cnt<=10){ 33 | if(cnt>=8 || cnt>=9 || cnt>=10 && cnt>=11){ 34 | break; 35 | } 36 | if(cnt<5){ 37 | cnt=cnt+1; 38 | printf("%d\n",cnt*cnt); 39 | continue; 40 | } 41 | cnt=cnt+1; 42 | if(cnt){ 43 | cnt=cnt+1; 44 | } 45 | if(!cnt){ 46 | cnt=cnt+1; 47 | } 48 | } 49 | printf("%d\n", cnt); 50 | printf("%d\n",cnt+1); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /testfiles/testfile2.txt: -------------------------------------------------------------------------------- 1 | /* B2 2 | * Decl * FuncDef * 3 | * Func * 4 | */ 5 | const int a=100; 6 | int b=10; 7 | 8 | void mult(int n[][2], int ans[]){ 9 | if(n[0][0]==1){ 10 | printf("%d\n",ans[0]); 11 | return; 12 | }else{ 13 | ans[0]=ans[0]*n[0][0]; 14 | n[0][0]=n[0][0]-1; 15 | mult(n, ans); 16 | return; 17 | } 18 | return; 19 | } 20 | 21 | int isRunYear(int year){ 22 | if(year%400==0){ 23 | return 1; 24 | }else{ 25 | if(year%100==0){ 26 | return 0; 27 | }else{ 28 | if(year%4==0){ 29 | return 1; 30 | }else{ 31 | return 0; 32 | } 33 | } 34 | return 0; 35 | } 36 | return 0; 37 | } 38 | 39 | int plus(int a, int b){ 40 | return a+b; 41 | } 42 | 43 | int justReturn1(){ 44 | return 1; 45 | } 46 | 47 | void printSmileFace(){ 48 | printf(":( )\n"); 49 | printf(":) ))\n"); 50 | printf(":) )))\n"); 51 | printf(":) ))))\n"); 52 | printf(":) )))))\n"); 53 | } 54 | 55 | int main(){ 56 | printf("20373091\n"); 57 | const int a[2]={101,101}; 58 | int b=100; 59 | int n[2][2]={{5,1},{a[0],a[1]}}; 60 | int ans[2]={1,400}; 61 | 62 | int ans1=isRunYear(ans[1]); 63 | int ans2=justReturn1(); 64 | int ans3=plus(ans1, ans2); 65 | 66 | printf("%d %d %d\n",a[0],b,ans1); 67 | printf("%d\n", n[1][1]); 68 | printf("%d\n", ans[1]); 69 | mult(n,ans); 70 | printSmileFace(); 71 | return 0; 72 | } -------------------------------------------------------------------------------- /testfiles/testfile3.txt: -------------------------------------------------------------------------------- 1 | /* B3 2 | * Decl x FuncDef x 3 | * Exp * Stmt * 4 | * Func x 5 | */ 6 | int main(){ 7 | printf("20373091\n"); 8 | const int a=1; 9 | const int b[2*2]={1,1}, c[2][2]={{1,2},{3,4}}, d=4; //genearal TODO 10 | int var1; 11 | int _var2 =((((a+1) * (b[0+1]-1))/4)%1)+1+c[0][0] , _var3[2][2]={{1,2},{3,4}}, _var4[3]={1,2,3}; 12 | int correct=1, uncorrect=0; 13 | var1=correct+1; 14 | _var3[0*0+1][0]=getint(); 15 | _var4[0]=0; 16 | int cnt=0; 17 | printf("%d %d %d %d\n",var1,_var2,_var3[1][0],_var4[2]); 18 | 19 | if(correct > uncorrect){ 20 | ; 21 | uncorrect+1; 22 | uncorrect=uncorrect+1; 23 | } 24 | if(correct != uncorrect){ 25 | if(correct == uncorrect){ 26 | uncorrect=uncorrect+1; 27 | } 28 | }else{ 29 | printf("%d %d\n",correct,uncorrect); 30 | } 31 | 32 | while(cnt<=10){ 33 | if(cnt>=8){ 34 | break; 35 | } 36 | if(cnt<5){ 37 | cnt=cnt+1; 38 | printf("%d\n",cnt*cnt); 39 | continue; 40 | } 41 | cnt=cnt+1; 42 | if(cnt){ 43 | cnt=cnt+1; 44 | } 45 | if(!cnt){ 46 | cnt=cnt+1; 47 | } 48 | } 49 | printf("%d\n", cnt); 50 | printf("%d\n",cnt+1); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /testfiles/testfile4.txt: -------------------------------------------------------------------------------- 1 | /* C4 2 | * Decl x FuncDef x 3 | * Exp * Stmt * 4 | * Func x 5 | */ 6 | int main(){ 7 | printf("20373091\n"); 8 | const int a=1; 9 | const int b=2, c=3, d=a+b; //genearal TODO 10 | const int one=1,two=2; 11 | int var1; 12 | int _var2 = -+-((((a+1) * (b-1))/4)%1)+1+c , _var3, _var4; 13 | int correct=1, uncorrect=0; 14 | var1=correct+1; 15 | _var3=getint(); 16 | _var4=0; 17 | int cnt=0; 18 | printf("%d %d %d %d\n",var1,_var2,_var3,_var4); 19 | 20 | if(correct > uncorrect){ 21 | ; 22 | uncorrect+1; 23 | uncorrect=uncorrect+1; 24 | } 25 | if(correct != uncorrect){ 26 | if(correct == uncorrect){ 27 | uncorrect=uncorrect+1; 28 | } 29 | }else{ 30 | printf("%d %d\n",correct,uncorrect); 31 | } 32 | 33 | while(cnt<=10){ 34 | if(cnt>=8){ 35 | break; 36 | } 37 | if(cnt<5){ 38 | cnt=cnt+1; 39 | printf("%d\n",cnt*cnt); 40 | continue; 41 | } 42 | cnt=cnt+1; 43 | if(cnt){ 44 | cnt=cnt+1; 45 | } 46 | if(!cnt){ 47 | cnt=cnt+1; 48 | } 49 | } 50 | { 51 | int a=10; 52 | if(a==9){ 53 | printf("%d\n", cnt); 54 | } 55 | } 56 | { 57 | 58 | } 59 | printf("%d\n", cnt); 60 | printf("%d\n",cnt+1); 61 | return 0; 62 | } -------------------------------------------------------------------------------- /testfiles/testfile5.txt: -------------------------------------------------------------------------------- 1 | /* C5 2 | * Decl * FuncDef * 3 | * Func * 4 | */ 5 | const int a=100; 6 | int b=10; 7 | 8 | void mult(int n, int ans){ 9 | if(n==1){ 10 | printf("%d\n",ans); 11 | return; 12 | }else{ 13 | mult(n-1, ans * n); 14 | return; 15 | } 16 | return; 17 | } 18 | 19 | int isRunYear(int year){ 20 | if(year%400==0){ 21 | return 1; 22 | }else{ 23 | if(year%100==0){ 24 | return 0; 25 | }else{ 26 | if(year%4==0){ 27 | return 1; 28 | }else{ 29 | return 0; 30 | } 31 | } 32 | return 0; 33 | } 34 | return 0; 35 | } 36 | 37 | int plus(int a, int b){ 38 | return a+b; 39 | } 40 | 41 | int plus3(int a, int b, int c){ 42 | return a+b; 43 | } 44 | 45 | int justReturn1(){ 46 | return 1; 47 | } 48 | 49 | void printSmileFace(){ 50 | printf(":( )\n"); 51 | printf(":) ))\n"); 52 | printf(":) )))\n"); 53 | printf(":) ))))\n"); 54 | printf(":) )))))\n"); 55 | } 56 | 57 | int main(){ 58 | printf("20373091\n"); 59 | int a=101; 60 | int b=100; 61 | int ans1=isRunYear(400); 62 | int ans2=justReturn1(); 63 | int ans3=plus(ans1, ans2); 64 | ans3=plus3(ans1,ans2,ans3); 65 | printf("%d %d %d\n",a,b,ans1); 66 | printf("%d\n", ans2); 67 | printf("%d\n", ans3); 68 | mult(5,1); 69 | printSmileFace(); 70 | return 0; 71 | } --------------------------------------------------------------------------------