commit 84827838e2967f910d40b29d8ce783214fd2486f Author: 邓智航 <23373333@buaa.edu.cn> Date: Wed Dec 10 17:58:17 2025 +0800 llvmir some opt diff --git a/2025编译技术实验文法定义及相关说明.pdf b/2025编译技术实验文法定义及相关说明.pdf new file mode 100644 index 0000000..b7115a7 Binary files /dev/null and b/2025编译技术实验文法定义及相关说明.pdf differ diff --git a/Compiler.java b/Compiler.java new file mode 100644 index 0000000..22f7088 --- /dev/null +++ b/Compiler.java @@ -0,0 +1,42 @@ +import java.nio.file.Files; +import java.nio.file.Paths; +import frontend.lexer.Lexer; +import frontend.lexer.TokenStream; +import frontend.parser.Parser; +import midend.Midend; +import midend.errorhandle.ErrorHandler; + +import error.Errors; +import midend.symbol.SymbolManager; + +public class Compiler { + public static void main(String[] args) { + Errors errors = new Errors(); + try { + String content = new String(Files.readAllBytes(Paths.get("testfile.txt"))); + String llvmFile = "llvm_ir.txt"; + String errorFile = "error.txt"; + Lexer lexer = new Lexer(content); + lexer.lex(errors); + TokenStream ts = new TokenStream(lexer.getTokens()); + Parser parser = new Parser(ts); + parser.parse(errors); + ErrorHandler errorHandler = new ErrorHandler(parser.getCompUnit()); + errorHandler.visit(errors); + // for (int i : SymbolManager.getSequence()) { + // System.out.print(i + " "); + // } + // System.out.println(); // TODO:debug + if (errors.size() > 0) { + StringBuilder sb = errors.toStringBuilder(); + Files.write(Paths.get(errorFile), sb.toString().getBytes()); + } else { + Midend midend = new Midend(parser.getCompUnit()); + midend.generateLLvmIr(); + midend.writeToFile(llvmFile); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/error/Error.java b/error/Error.java new file mode 100644 index 0000000..88011da --- /dev/null +++ b/error/Error.java @@ -0,0 +1,27 @@ +package error; + +public class Error { + private int line; + private ErrorType type; + + public Error(int line, ErrorType type) { + this.line = line; + this.type = type; + } + + public void printError() { + System.out.println(this.line + " " + this.type); + } + + public int getLine() { + return this.line; + } + + public ErrorType getType() { + return this.type; + } + + public String toString() { + return this.line + " " + this.type + "\n"; + } +} diff --git a/error/ErrorType.java b/error/ErrorType.java new file mode 100644 index 0000000..c4b2283 --- /dev/null +++ b/error/ErrorType.java @@ -0,0 +1,17 @@ +package error; + +public enum ErrorType { + a, + b, + c, + d, + e, + f, + g, + h, + i, + j, + k, + l, + m +} diff --git a/error/Errors.java b/error/Errors.java new file mode 100644 index 0000000..38ed887 --- /dev/null +++ b/error/Errors.java @@ -0,0 +1,43 @@ +package error; + +import java.util.ArrayList; + +public class Errors { + private ArrayList errors; + + public Errors() { + this.errors = new ArrayList(); + } + + public void addError(Error error) { + int index = 0; + if (this.errors.size() == 0 || + this.errors.get(this.errors.size() - 1).getLine() <= error.getLine()) { + this.errors.add(error); + return; + } + if (this.errors.get(0).getLine() > error.getLine()) { + this.errors.add(index, error); + return; + } + for (int i = this.errors.size() - 1; i >= 0; i--) { + if (this.errors.get(i).getLine() <= error.getLine()) { + index = i + 1; + break; + } + } + this.errors.add(index, error); + } + + public int size() { + return this.errors.size(); + } + + public StringBuilder toStringBuilder() { + StringBuilder sb = new StringBuilder(); + for (Error error : this.errors) { + sb.append(error.toString()); + } + return sb; + } +} diff --git a/frontend/.DS_Store b/frontend/.DS_Store new file mode 100644 index 0000000..b6a53e3 Binary files /dev/null and b/frontend/.DS_Store differ diff --git a/frontend/ast/.DS_Store b/frontend/ast/.DS_Store new file mode 100644 index 0000000..b5ccaa0 Binary files /dev/null and b/frontend/ast/.DS_Store differ diff --git a/frontend/ast/CompUnit.java b/frontend/ast/CompUnit.java new file mode 100644 index 0000000..25921f7 --- /dev/null +++ b/frontend/ast/CompUnit.java @@ -0,0 +1,63 @@ +package frontend.ast; + +import java.util.ArrayList; + +import error.Errors; +import frontend.ast.decl.Decl; +import frontend.ast.func.FuncDef; +import frontend.ast.func.MainFuncDef; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; + +public class CompUnit extends Node { + public CompUnit(TokenStream ts) { + super(SyntaxType.COMP_UNIT, ts); + } + + public void parse(Errors errors) { + while (getCurrToken() != null) { + if (this.ts.peek(1).getType() == TokenType.MAINTK) { + MainFuncDef mainFuncDef = new MainFuncDef(this.ts); + mainFuncDef.parse(errors); + addChild(mainFuncDef); + } else if (this.ts.peek(2).getType() == TokenType.LPARENT) { + FuncDef funcdef = new FuncDef(this.ts); + funcdef.parse(errors); + addChild(funcdef); + } else { + Decl decl = new Decl(this.ts); + decl.parse(errors); + addChild(decl); + } + } + } + + public ArrayList GetDecls() { + ArrayList decls = new ArrayList(); + for (int i = 0; i < this.getChildren().size(); i++) { + if (this.getChild(i) instanceof Decl) { + decls.add((Decl) this.getChild(i)); + } + } + return decls; + } + + public ArrayList GetFuncDefs() { + ArrayList funcDefs = new ArrayList(); + for (int i = 0; i < this.getChildren().size(); i++) { + if (this.getChild(i) instanceof FuncDef) { + funcDefs.add((FuncDef) this.getChild(i)); + } + } + return funcDefs; + } + + public MainFuncDef GetMainFuncDef() { + for (int i = 0; i < this.getChildren().size(); i++) { + if (this.getChild(i) instanceof MainFuncDef) { + return (MainFuncDef) this.getChild(i); + } + } + return null; + } +} diff --git a/frontend/ast/Node.java b/frontend/ast/Node.java new file mode 100644 index 0000000..744232c --- /dev/null +++ b/frontend/ast/Node.java @@ -0,0 +1,248 @@ +package frontend.ast; + +import frontend.ast.decl.Decl; +import frontend.ast.func.MainFuncDef; +import frontend.lexer.Token; +import frontend.lexer.TokenStream; +import frontend.ast.block.BlockItem; +import frontend.ast.block.ForStmt; +import frontend.ast.block.Block; +import frontend.ast.decl.ConstDecl; +import frontend.ast.decl.ConstDef; +import frontend.ast.decl.VarDef; +import frontend.ast.exp.UnaryExp; +import frontend.ast.func.FuncDef; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenType; +import frontend.ast.exp.LVal; +import frontend.ast.block.Stmt; +import frontend.ast.exp.Exp; + +import error.Errors; +import error.Error; +import error.ErrorType; + +import midend.symbol.FuncSymbol; +import midend.symbol.SymbolManager; +import midend.symbol.SymbolType; +import midend.symbol.Symbol; + +import java.util.ArrayList; +import java.util.HashMap; + +public class Node { + private SyntaxType type; + private ArrayList children; + protected TokenStream ts; + + public Node(SyntaxType type, TokenStream ts) { + this.type = type; + this.ts = ts; + this.children = new ArrayList<>(); + } + + public void addChild(Node child) { + this.children.add(child); + } + + public String toString() { + return "<" + type.toString() + ">\n"; + } + + public Token getCurrToken() { + return ts.peek(0); + } // not change index in ts + + public Token read() { + return ts.read(); + } // change index in ts + + public String getInfo() { + String info = ""; + for (Node child : children) { + info += child.getInfo(); + } + if (!(this instanceof Decl || this instanceof BlockItem)) { + info += this.toString(); + } + return info; + } + + public ArrayList getChildren() { + return children; + } + + public Node getChild(int index) { + return children.get(index); + } + + public void fillSymbolTable(boolean isInFunc, + boolean isInFor, Errors errors) { + if (this instanceof CompUnit || (this instanceof Block && !isInFunc)) { + SymbolManager.addSymbolTable(); + } + if (this instanceof Decl) { + handleDecl(errors); + } + if (this instanceof FuncDef) { + handleFuncDef(errors); + return; + } + if (this instanceof UnaryExp && children.get(0) instanceof TokenNode) { + handleFuncCall(errors); + return; + } + if (this instanceof Stmt && getChild(0) instanceof TokenNode + && ((TokenNode) getChild(0)).getType() == TokenType.FORTK) { + for (Node child: children) { + child.fillSymbolTable(false, true, errors); + } + return; + } + if (this instanceof Stmt && getChild(0) instanceof TokenNode + && (((TokenNode) getChild(0)).getType() == TokenType.BREAKTK + || ((TokenNode) getChild(0)).getType() == TokenType.CONTINUETK)) { + if (!isInFor) { + errors.addError(new Error(((TokenNode) getChild(0)).getLine(), ErrorType.m)); + } + } + if (this instanceof TokenNode) { + handleTokenNode(errors); + } + if (this instanceof Stmt && getChild(0) instanceof LVal) { // error handle + handleErrorhInStmt(errors); + } + if (this instanceof ForStmt) { + handleErrorhInStmt(errors); + } + if (this instanceof Stmt && getChild(0) instanceof TokenNode + && ((TokenNode) getChild(0)).getType() == TokenType.PRINTFTK) { + handleMatchFormat(errors); + } + if (this instanceof MainFuncDef) { + ((MainFuncDef) this).checkReturnNode(errors); + } + for (Node child : children) { + child.fillSymbolTable(false, isInFor, errors); + } + if (this instanceof CompUnit || this instanceof Block) { + SymbolManager.releaseSymbolTable(); + // System.out.println("release a symbol table"); + } + // !注意哪些是直接return的,这些直接return的是否处理完整,因为他们直接省略了后续的递归,要么在子方法里重新递归了,要么没有递归的必要,仔细检查!!! + } + + public void handleDecl(Errors errors) { + if (this.children.get(0) instanceof ConstDecl) { + Node constdecl = this.children.get(0); + for (int i = 2; i < constdecl.children.size(); i = i + 2) { + SymbolManager.addSymbol(((ConstDef) constdecl.children.get(i)).getSymbol(), errors); + } + } else { + Node vardecl = this.children.get(0); + if (((TokenNode) vardecl.children.get(0)).getType() == TokenType.STATICTK) { + for (int i = 2; i < vardecl.children.size(); i = i + 2) { + SymbolManager.addSymbol( + ((VarDef) vardecl.children.get(i)).getSymbol(1), errors); + // System.out.println(((VarDef) + // vardecl.children.get(i)).getSymbol(1).toString()); + } + } else { + for (int i = 1; i < vardecl.children.size(); i = i + 2) { + SymbolManager.addSymbol( + ((VarDef) vardecl.children.get(i)).getSymbol(0), errors); + // System.out.println(((VarDef) + // vardecl.children.get(i)).getSymbol(0).toString()); + } + } + } + } + + public void handleFuncDef(Errors errors) { + FuncDef funcdef = (FuncDef) this; + Symbol funcSymbol = funcdef.getSymbol(); + // System.out.println(funcSymbol.toString()); + // System.out.println(SymbolManager.getSymbolTableSize()); + SymbolManager.addSymbol(funcSymbol, errors); + SymbolManager.addSymbolTable(); + funcdef.addParamSymbol(funcSymbol, errors); + if (funcSymbol.getType() == SymbolType.VOID_FUNC) { +// int returnStatus = funcdef.getReturnStatus(); +// TokenNode returnNode = funcdef.getReturnNode(); + HashMap returnNodes = new HashMap<>(); + funcdef.getReturnNodes(returnNodes); + for (TokenNode returnNode : returnNodes.keySet()) { + if (returnNodes.get(returnNode) == 2) { + errors.addError(new Error(returnNode.getLine(), ErrorType.f)); + } + } + } else if (funcSymbol.getType() == SymbolType.INT_FUNC) { + funcdef.checkReturnNode(errors); + } + // 填参数和块里定义的参数,一个问题是这时的释放是该如何判断 + for (Node child : children) { + if (child instanceof Block) { + ((Block) child).fillSymbolTable(true, false, errors); + } + } + } + + public void handleTokenNode(Errors errors) { + TokenNode tokenNode = (TokenNode) this; + if (tokenNode.getType() == TokenType.IDENFR && !tokenNode.getName().equals("getint")) { + Symbol symbol = SymbolManager.getSymbol(tokenNode.getName()); + if (symbol == null) { + errors.addError(new Error(tokenNode.getLine(), ErrorType.c)); + } + } + } + + public void handleFuncCall(Errors errors) { + UnaryExp ue = (UnaryExp) this; + ue.handleFuncCall(errors); + } + + public void getReturnNodes(HashMap returnNodess) { // 0: no return, 1: return void, 2: return int + for (int i = 0; i < children.size(); i++) { + if (getChild(i) instanceof TokenNode && + ((TokenNode) getChild(i)).getType() == TokenType.RETURNTK) { + if (i == children.size() - 1) { + returnNodess.put((TokenNode) getChild(i), 1); + }else if (getChild(i+1) instanceof TokenNode) { + returnNodess.put((TokenNode) getChild(i), 1); + }else { + returnNodess.put((TokenNode) getChild(i), 2); + } + } else if (!(getChild(i) instanceof TokenNode)) { + getChild(i).getReturnNodes(returnNodess); + } + } + } + + public void handleErrorhInStmt(Errors errors) { + for (int i = 0; 4 * i < children.size(); i++){ + TokenNode idenfr = (TokenNode) getChild(4 * i).getChild(0); + Symbol symbol = SymbolManager.getSymbol(idenfr.getName()); + if (symbol != null) { + if (symbol.getType() == SymbolType.CONST_INT + || symbol.getType() == SymbolType.CONST_INT_ARRAY) { + errors.addError(new Error(idenfr.getLine(), ErrorType.h)); + } + } + } + } + + public void handleMatchFormat(Errors errors) { + TokenNode strCons = (TokenNode) getChild(2); + int formatNum = strCons.getFormatNum(); + int expNum = 0; + for (Node child : children) { + if (child instanceof Exp) { + expNum++; + } + } + if (formatNum != expNum) { + errors.addError(new Error(((TokenNode) getChild(0)).getLine(), ErrorType.l)); + } + } +} diff --git a/frontend/ast/NodeStack.java b/frontend/ast/NodeStack.java new file mode 100644 index 0000000..f689a03 --- /dev/null +++ b/frontend/ast/NodeStack.java @@ -0,0 +1,23 @@ +package frontend.ast; + +import java.util.ArrayList; + +public class NodeStack { + private ArrayList stack; + + public NodeStack() { + stack = new ArrayList(); + } + + public void push(Node node) { + stack.add(node); + } + + public Node pop() { + return stack.remove(stack.size() - 1); + } + + public int size() { + return stack.size(); + } +} diff --git a/frontend/ast/SyntaxType.java b/frontend/ast/SyntaxType.java new file mode 100644 index 0000000..8524924 --- /dev/null +++ b/frontend/ast/SyntaxType.java @@ -0,0 +1,66 @@ +package frontend.ast; + +public enum SyntaxType { + COMP_UNIT("CompUnit"), + + BTYPE("BType"), + + DECL("Decl"), + CONST_DECL("ConstDecl"), + VAR_DECL("VarDecl"), + + CONST_DEF("ConstDef"), + CONST_INIT_VAL("ConstInitVal"), + VAR_DEF("VarDef"), + INIT_VAL("InitVal"), + + FUNC_DEF("FuncDef"), + MAIN_FUNC_DEF("MainFuncDef"), + FUNC_TYPE("FuncType"), + + FUNC_FORMAL_PARAM("FuncFParam"), + FUNC_FORMAL_PARAM_S("FuncFParams"), + FUNC_REAL_PARAM_S("FuncRParams"), + + BLOCK("Block"), + BLOCK_ITEM("BlockItem"), + + STMT("Stmt"), + FOR_STMT("ForStmt"), + + UNARY_OP("UnaryOp"), + IDENT("Ident"), + + EXP("Exp"), + LVAL_EXP("LVal"), + PRIMARY_EXP("PrimaryExp"), + UNARY_EXP("UnaryExp"), + MUL_EXP("MulExp"), + ADD_EXP("AddExp"), + REL_EXP("RelExp"), + EQ_EXP("EqExp"), + LAND_EXP("LAndExp"), + LOR_EXP("LOrExp"), + CONST_EXP("ConstExp"), + COND_EXP("Cond"), + + NUMBER("Number"), + CHARACTER("Character"), + + INT_CONST("IntConst"), + STRING_CONST("StringConst"), + CHAR_CONST("CharConst"), + + TOKEN("Token"); + + private final String Name; + + SyntaxType(String Name) { + this.Name = Name; + } + + @Override + public String toString() { + return this.Name; + } +} diff --git a/frontend/ast/block/Block.java b/frontend/ast/block/Block.java new file mode 100644 index 0000000..57f5f80 --- /dev/null +++ b/frontend/ast/block/Block.java @@ -0,0 +1,49 @@ +package frontend.ast.block; + +import java.util.ArrayList; + +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; + +public class Block extends Node { + private boolean isFuncBlock; + + public Block(TokenStream ts) { + super(SyntaxType.BLOCK, ts); + isFuncBlock = false; + } + + public void parse(Errors errors) { + TokenNode lbrace = new TokenNode(this.ts); + addChild(lbrace); + while (getCurrToken().getType() != TokenType.RBRACE) { + BlockItem bit = new BlockItem(this.ts); + bit.parse(errors); + addChild(bit); + } + TokenNode rbrace = new TokenNode(this.ts); + addChild(rbrace); + } + + public ArrayList getBlockItems() { + ArrayList blockItems = new ArrayList<>(); + for (int i = 0; i < getChildren().size(); i++) { + if (getChild(i) instanceof BlockItem) { + blockItems.add((BlockItem) getChild(i)); + } + } + return blockItems; + } + + public boolean isFuncBlock() { + return isFuncBlock; + } + + public void setIsFuncBlock(boolean isFuncBlock) { + this.isFuncBlock = isFuncBlock; + } +} diff --git a/frontend/ast/block/BlockItem.java b/frontend/ast/block/BlockItem.java new file mode 100644 index 0000000..ba18d81 --- /dev/null +++ b/frontend/ast/block/BlockItem.java @@ -0,0 +1,28 @@ +package frontend.ast.block; + +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.decl.Decl; + +public class BlockItem extends Node { + public BlockItem(TokenStream ts) { + super(SyntaxType.BLOCK_ITEM, ts); + } + + public void parse(Errors errors) { + if (getCurrToken().getType() == TokenType.CONSTTK + || getCurrToken().getType() == TokenType.STATICTK + || getCurrToken().getType() == TokenType.INTTK) { + Decl decl = new Decl(this.ts); + decl.parse(errors); + addChild(decl); + } else { + Stmt stmt = new Stmt(this.ts); + stmt.parse(errors); + addChild(stmt); + } + } +} diff --git a/frontend/ast/block/ForStmt.java b/frontend/ast/block/ForStmt.java new file mode 100644 index 0000000..21c5056 --- /dev/null +++ b/frontend/ast/block/ForStmt.java @@ -0,0 +1,57 @@ +package frontend.ast.block; + +import frontend.ast.SyntaxType; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.Node; +import frontend.ast.exp.Exp; +import frontend.ast.exp.LVal; + +import java.util.ArrayList; + +import error.Errors; + +public class ForStmt extends Node { + public ForStmt(TokenStream ts) { + super(SyntaxType.FOR_STMT, ts); + } + + public void parse(Errors errors) { + handleAssign(errors); + while (getCurrToken().getType() == TokenType.COMMA) { + addChild(new TokenNode(ts)); // comma + handleAssign(errors); + } + } + + public void handleAssign(Errors errors) { + LVal lval = new LVal(this.ts); + lval.parse(errors); + addChild(lval); + addChild(new TokenNode(ts)); // assign + Exp exp = new Exp(this.ts); + exp.parse(errors); + addChild(exp); + } + + public ArrayList getLValList() { + ArrayList lvalList = new ArrayList<>(); + for (int i = 0; i < getChildren().size(); i++) { + if (getChild(i) instanceof LVal) { + lvalList.add((LVal) getChild(i)); + } + } + return lvalList; + } + + public ArrayList getExpList() { + ArrayList expList = new ArrayList<>(); + for (int i = 0; i < getChildren().size(); i++) { + if (getChild(i) instanceof Exp) { + expList.add((Exp) getChild(i)); + } + } + return expList; + } +} diff --git a/frontend/ast/block/Stmt.java b/frontend/ast/block/Stmt.java new file mode 100644 index 0000000..cf40506 --- /dev/null +++ b/frontend/ast/block/Stmt.java @@ -0,0 +1,274 @@ +package frontend.ast.block; + +import error.Errors; + +import java.util.ArrayList; + +import error.Error; +import error.ErrorType; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import frontend.ast.exp.Exp; +import frontend.ast.exp.Cond; +import frontend.ast.exp.LVal; + +public class Stmt extends Node { + private boolean getint; + + public Stmt(TokenStream ts) { + super(SyntaxType.STMT, ts); + getint = false; + } + + public void parse(Errors errors) { + if (getCurrToken().getType() == TokenType.LBRACE) { + Block block = new Block(this.ts); + block.parse(errors); + addChild(block); + } else if (getCurrToken().getType() == TokenType.IFTK) { + handleIf(errors); + } else if (getCurrToken().getType() == TokenType.FORTK) { + handleFor(errors); + } else if (getCurrToken().getType() == TokenType.BREAKTK) { + TokenNode breakkk = new TokenNode(this.ts); + addChild(breakkk); + if (getCurrToken().getType() == TokenType.SEMICN) { + TokenNode semicolon = new TokenNode(this.ts); + addChild(semicolon); + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.i)); + } + } else if (getCurrToken().getType() == TokenType.CONTINUETK) { + TokenNode continuekk = new TokenNode(this.ts); + addChild(continuekk); + if (getCurrToken().getType() == TokenType.SEMICN) { + TokenNode semicolon = new TokenNode(this.ts); + addChild(semicolon); + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.i)); + } + } else if (getCurrToken().getType() == TokenType.RETURNTK) { + handleReturn(errors); + } else if (getCurrToken().getType() == TokenType.PRINTFTK) { + handlePrintf(errors); + } else { + handleAssign(errors); + } + } + + public void handleIf(Errors errors) { + TokenNode ifkk = new TokenNode(this.ts); + addChild(ifkk); + TokenNode lparent = new TokenNode(this.ts); + addChild(lparent); + Cond cond = new Cond(this.ts); + cond.parse(errors); + addChild(cond); + if (getCurrToken().getType() == TokenType.RPARENT) { + TokenNode rparent = new TokenNode(this.ts); + addChild(rparent); + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.j)); + } + Stmt stmt = new Stmt(this.ts); + stmt.parse(errors); + addChild(stmt); + if (getCurrToken().getType() == TokenType.ELSETK) { + TokenNode elsekk = new TokenNode(this.ts); + addChild(elsekk); + Stmt elseStmt = new Stmt(this.ts); + elseStmt.parse(errors); + addChild(elseStmt); + } + } + + public void handleFor(Errors errors) { + TokenNode forkk = new TokenNode(this.ts); + addChild(forkk); + TokenNode lparent = new TokenNode(this.ts); + addChild(lparent); + if (getCurrToken().getType() == TokenType.SEMICN) { + TokenNode semicolon = new TokenNode(this.ts); + addChild(semicolon); + } else { + ForStmt fst = new ForStmt(this.ts); + fst.parse(errors); + addChild(fst); + TokenNode semicolon = new TokenNode(this.ts); + addChild(semicolon); + } + if (getCurrToken().getType() == TokenType.SEMICN) { + TokenNode semicolon = new TokenNode(this.ts); + addChild(semicolon); + } else { + Cond cond = new Cond(this.ts); + cond.parse(errors); + addChild(cond); + TokenNode semicolon = new TokenNode(this.ts); + addChild(semicolon); + } + if (getCurrToken().getType() == TokenType.RPARENT) { + TokenNode rparent = new TokenNode(this.ts); + addChild(rparent); + } else { + ForStmt fst = new ForStmt(this.ts); + fst.parse(errors); + addChild(fst); + TokenNode rparent = new TokenNode(this.ts); + addChild(rparent); + } + Stmt stmt = new Stmt(this.ts); + stmt.parse(errors); + addChild(stmt); + } + + public void handleReturn(Errors errors) { + TokenNode returnkk = new TokenNode(this.ts); + addChild(returnkk); + if (currentIsExp()) { + Exp exp = new Exp(this.ts); + exp.parse(errors); + addChild(exp); + } + if (getCurrToken().getType() == TokenType.SEMICN) { + TokenNode semicolon = new TokenNode(this.ts); + addChild(semicolon); + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.i)); + } + } + + public void handlePrintf(Errors errors) { + TokenNode printfkk = new TokenNode(this.ts); + addChild(printfkk); + addChild(new TokenNode(this.ts)); // lparent + addChild(new TokenNode(this.ts)); // strconst + while (getCurrToken().getType() == TokenType.COMMA) { + addChild(new TokenNode(this.ts)); // comma + Exp exp = new Exp(this.ts); + exp.parse(errors); + addChild(exp); + } + if (getCurrToken().getType() != TokenType.RPARENT) { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.j)); + } else { + addChild(new TokenNode(this.ts)); // rparent + } + if (getCurrToken().getType() != TokenType.SEMICN) { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.i)); + } else { + addChild(new TokenNode(this.ts)); // semicolon + } + } + + public void handleAssign(Errors errors) { + if (getCurrToken().getType() == TokenType.IDENFR) { + if (this.ts.peek(1).getType() == TokenType.ASSIGN) { + LVal lval = new LVal(this.ts); + lval.parse(errors); + addChild(lval); + addChild(new TokenNode(this.ts)); // assign + if (getCurrToken().getValue().equals("getint")) { + getint = true; + } + Exp exp = new Exp(this.ts); + exp.parse(errors); + addChild(exp); + if (getCurrToken().getType() == TokenType.SEMICN) { + addChild(new TokenNode(this.ts)); // semicolon + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.i)); + } + } else if (this.ts.peek(1).getType() == TokenType.LBRACK) { + int start = this.ts.getCurrentIndex(); + LVal lval = new LVal(this.ts); + lval.parse(errors); + if (getCurrToken().getType() == TokenType.ASSIGN) { + addChild(lval); + addChild(new TokenNode(this.ts)); // assign + if (getCurrToken().getValue().equals("getint")) { + getint = true; + } + handleExpInAssign(errors); + } else { + this.ts.resetIndex(start); + // parse exp ; + handleExpInAssign(errors); + } + } else { + handleExpInAssign(errors); + } + } else { + if (currentIsExp()) { + handleExpInAssign(errors); + } else { + if (getCurrToken().getType() == TokenType.SEMICN) { + addChild(new TokenNode(this.ts)); // semicolon + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.i)); + } + } + } + } + + public void handleExpInAssign(Errors errors) { + Exp exp = new Exp(this.ts); + exp.parse(errors); + addChild(exp); + if (getCurrToken().getType() == TokenType.SEMICN) { + addChild(new TokenNode(this.ts)); // semicolon + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.i)); + } + } + + public boolean currentIsExp() { + TokenType t = getCurrToken().getType(); + return t == TokenType.PLUS || t == TokenType.MINU || t == TokenType.NOT + || t == TokenType.IDENFR || t == TokenType.LPARENT || t == TokenType.INTCON; + } + + public boolean isGetint() { + return getint; + } + + public ArrayList getExpList() { + ArrayList expList = new ArrayList<>(); + for (int i = 0; i < getChildren().size(); i++) { + if (getChild(i) instanceof Exp) { + expList.add((Exp) getChild(i)); + } + } + return expList; + } + + public Cond getCond() { //just for fortype stmt + for (int i = 0; i < getChildren().size(); i++) { + if (getChild(i) instanceof Cond) { + return (Cond) getChild(i); + } + } + return null; + } + + public ForStmt getinitStmt() { + if (getChild(2) instanceof ForStmt) { + return (ForStmt) getChild(2); + } + return null; + } + + public ForStmt getStepStmt() { + if (getChild(getChildren().size() - 3) instanceof ForStmt) { + return (ForStmt) getChild(getChildren().size() - 3); + } + return null; + } + + public Stmt getBodyStmt() { + return (Stmt) getChild(getChildren().size() - 1); + } +} diff --git a/frontend/ast/decl/ConstDecl.java b/frontend/ast/decl/ConstDecl.java new file mode 100644 index 0000000..015f087 --- /dev/null +++ b/frontend/ast/decl/ConstDecl.java @@ -0,0 +1,51 @@ +package frontend.ast.decl; + +import error.Errors; +import error.ErrorType; + +import java.util.ArrayList; + +import error.Error; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; + +public class ConstDecl extends Node { + public ConstDecl(TokenStream ts) { + super(SyntaxType.CONST_DECL, ts); + } + + public void parse(Errors errors) { + TokenNode constkk = new TokenNode(this.ts); + addChild(constkk); + TokenNode intkk = new TokenNode(this.ts); + addChild(intkk); + while (true) { + ConstDef cdef = new ConstDef(this.ts); + cdef.parse(errors); + addChild(cdef); + if (getCurrToken().getType() != TokenType.COMMA) { + break; + } else { + TokenNode comma = new TokenNode(this.ts); + addChild(comma); + } + } + if (getCurrToken().getType() != TokenType.SEMICN) { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.i)); + } else { + TokenNode semicoln = new TokenNode(this.ts); + addChild(semicoln); + } + } + + public ArrayList GetConstDefs() { + ArrayList constDefs = new ArrayList<>(); + for (int i = 2; i < getChildren().size(); i += 2) { + constDefs.add((ConstDef) getChild(i)); + } + return constDefs; + } +} diff --git a/frontend/ast/decl/ConstDef.java b/frontend/ast/decl/ConstDef.java new file mode 100644 index 0000000..51166b8 --- /dev/null +++ b/frontend/ast/decl/ConstDef.java @@ -0,0 +1,66 @@ +package frontend.ast.decl; + +import error.Error; +import error.ErrorType; +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.ast.exp.ConstExp; +import frontend.ast.token.TokenNode; +import frontend.ast.val.ConstInitVal; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import midend.symbol.ArraySymbol; +import midend.symbol.Symbol; +import midend.symbol.SymbolType; + +public class ConstDef extends Node { + private boolean isArray; + + public ConstDef(TokenStream ts) { + super(SyntaxType.CONST_DEF, ts); + isArray = false; + } + + public void parse(Errors errors) { + TokenNode ident = new TokenNode(this.ts); + addChild(ident); + if (getCurrToken().getType() == TokenType.LBRACK) { + TokenNode lbrack = new TokenNode(this.ts); + addChild(lbrack); + isArray = true; + ConstExp cep = new ConstExp(this.ts); + cep.parse(errors); + addChild(cep); + if (getCurrToken().getType() == TokenType.RBRACK) { + TokenNode rbrack = new TokenNode(this.ts); + addChild(rbrack); + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.k)); + } + } + TokenNode assign = new TokenNode(this.ts); + addChild(assign); + ConstInitVal civ = new ConstInitVal(this.ts); + civ.parse(errors); + addChild(civ); + } + + public Symbol getSymbol() { + if (isArray) { + TokenNode tn = (TokenNode) getChild(0); + ArraySymbol arraySymbol = new ArraySymbol(tn.getName(), + SymbolType.CONST_INT_ARRAY, tn.getLine(), + ((ConstExp) getChild(2)).getValue()); + arraySymbol.addValue(((ConstInitVal) getChild(getChildren().size() - 1)).getValue()); + arraySymbol.fullValue(); + return arraySymbol; + } else { + TokenNode tn = (TokenNode) getChild(0); + Symbol valueSymbol = new Symbol(tn.getName(), + SymbolType.CONST_INT, tn.getLine()); + valueSymbol.addValue(((ConstInitVal) getChild(getChildren().size() - 1)).getValue()); + return valueSymbol; + } + } +} diff --git a/frontend/ast/decl/Decl.java b/frontend/ast/decl/Decl.java new file mode 100644 index 0000000..6caf222 --- /dev/null +++ b/frontend/ast/decl/Decl.java @@ -0,0 +1,25 @@ +package frontend.ast.decl; + +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; + +public class Decl extends Node { + public Decl(TokenStream ts) { + super(SyntaxType.DECL, ts); + } + + public void parse(Errors errors) { + if (getCurrToken().getType() == TokenType.CONSTTK) { + ConstDecl cd = new ConstDecl(this.ts); + cd.parse(errors); + addChild(cd); + } else { + VarDecl vd = new VarDecl(this.ts); + vd.parse(errors); + addChild(vd); + } + } +} diff --git a/frontend/ast/decl/VarDecl.java b/frontend/ast/decl/VarDecl.java new file mode 100644 index 0000000..516d18c --- /dev/null +++ b/frontend/ast/decl/VarDecl.java @@ -0,0 +1,59 @@ +package frontend.ast.decl; + +import error.ErrorType; +import error.Errors; + +import java.util.ArrayList; + +import error.Error; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; + +public class VarDecl extends Node { + public VarDecl(TokenStream ts) { + super(SyntaxType.VAR_DECL, ts); + } + + public void parse(Errors errors) { + if (getCurrToken().getType() == TokenType.STATICTK) { + TokenNode staitckk = new TokenNode(ts); + addChild(staitckk); + } + TokenNode intkk = new TokenNode(ts); + addChild(intkk); + while (true) { + VarDef vdf = new VarDef(ts); + vdf.parse(errors); + addChild(vdf); + if (getCurrToken().getType() == TokenType.COMMA) { + TokenNode comma = new TokenNode(ts); + addChild(comma); + } else { + break; + } + } + if (getCurrToken().getType() == TokenType.SEMICN) { + TokenNode semicn = new TokenNode(ts); + addChild(semicn); + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.i)); + } + } + + public ArrayList GetVarDefs() { + ArrayList varDefs = new ArrayList(); + if (getChild(1) instanceof VarDef) { + for (int i = 1; i < getChildren().size(); i += 2) { + varDefs.add((VarDef) getChild(i)); + } + } else { + for (int i = 2; i < getChildren().size(); i += 2) { + varDefs.add((VarDef) getChild(i)); + } + } + return varDefs; + } +} diff --git a/frontend/ast/decl/VarDef.java b/frontend/ast/decl/VarDef.java new file mode 100644 index 0000000..44056ef --- /dev/null +++ b/frontend/ast/decl/VarDef.java @@ -0,0 +1,117 @@ +package frontend.ast.decl; + +import error.Errors; +import error.Error; +import error.ErrorType; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.ast.exp.ConstExp; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.val.InitVal; + +import midend.symbol.Symbol; +import midend.symbol.SymbolManager; +import midend.symbol.SymbolType; +import midend.symbol.ArraySymbol; + +public class VarDef extends Node { + private boolean isArray; + + public VarDef(TokenStream ts) { + super(SyntaxType.VAR_DEF, ts); + isArray = false; + } + + public void parse(Errors errors) { + TokenNode ident = new TokenNode(this.ts); + addChild(ident); + if (getCurrToken().getType() == TokenType.LBRACK) { + TokenNode lbrack = new TokenNode(this.ts); + addChild(lbrack); + isArray = true; + ConstExp cep = new ConstExp(this.ts); + cep.parse(errors); + addChild(cep); + if (getCurrToken().getType() == TokenType.RBRACK) { + TokenNode rbrack = new TokenNode(this.ts); + addChild(rbrack); + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.k)); + } + } + if (getCurrToken().getType() == TokenType.ASSIGN) { + TokenNode assign = new TokenNode(this.ts); + addChild(assign); + InitVal itv = new InitVal(this.ts); + itv.parse(errors); + addChild(itv); + } + } + + public Symbol getSymbol(int isStatic) { + if (isStatic == 1) { //static修饰的变量有初值 + if (isArray) { + TokenNode tn = (TokenNode) getChild(0); + ArraySymbol arraySymbol = new ArraySymbol(tn.getName(), + SymbolType.STATIC_INT_ARRAY, tn.getLine(), + ((ConstExp) getChild(2)).getValue()); + if (HaveInitVal()) { + arraySymbol.addValue(((InitVal) getChild(getChildren().size() - 1)).getValue()); + } + arraySymbol.fullValue(); + return arraySymbol; + } else { + TokenNode tn = (TokenNode) getChild(0); + Symbol valueSymbol = new Symbol(tn.getName(), + SymbolType.STATIC_INT, tn.getLine()); + if (HaveInitVal()) { + valueSymbol.addValue(((InitVal) getChild(getChildren().size() - 1)).getValue()); + } else { + valueSymbol.addValue(0); + } + return valueSymbol; + } + } else { //要判断是否为全局变量,如果为全局变量,也应该赋初值 + if (isArray) { + TokenNode tn = (TokenNode) getChild(0); + ArraySymbol arraySymbol = new ArraySymbol(tn.getName(), + SymbolType.INT_ARRAY, tn.getLine(), + ((ConstExp) getChild(2)).getValue()); + if (SymbolManager.IsGlobal()) { + if (HaveInitVal()) { + arraySymbol.addValue(((InitVal) getChild( + getChildren().size() - 1)).getValue()); + } + arraySymbol.fullValue(); + } + return arraySymbol; + } else { + TokenNode tn = (TokenNode) getChild(0); + Symbol symbol = new Symbol(tn.getName(), + SymbolType.INT, tn.getLine()); + if (SymbolManager.IsGlobal()) { + if (HaveInitVal()) { + symbol.addValue(((InitVal) getChild( + getChildren().size() - 1)).getValue()); + } else { + symbol.addValue(0); + } + } + return symbol; + } + } + } + + public boolean HaveInitVal() { + return getChild(getChildren().size() - 1) instanceof InitVal; + } + + public InitVal getInitVal() { + if (HaveInitVal()) { + return (InitVal) getChild(getChildren().size() - 1); + } + return null; + } +} diff --git a/frontend/ast/exp/AddExp.java b/frontend/ast/exp/AddExp.java new file mode 100644 index 0000000..9a322a6 --- /dev/null +++ b/frontend/ast/exp/AddExp.java @@ -0,0 +1,73 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.NodeStack; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import midend.symbol.SymbolManager; +import error.Errors; + +public class AddExp extends Node { + public AddExp(TokenStream ts) { + super(SyntaxType.ADD_EXP, ts); + } + + public void parse(Errors errors) { + NodeStack stack = new NodeStack(); + while (true) { + MulExp mep = new MulExp(this.ts); + mep.parse(errors); + stack.push(mep); + if (isAddOp()) { + stack.push(new TokenNode(ts)); // addop + } else { + break; + } + } + if (stack.size() == 1) { + this.addChild((MulExp) stack.pop()); + } else { + AddExp temp = this; + while (stack.size() > 1) { + AddExp ae = new AddExp(this.ts); + MulExp mep = (MulExp) stack.pop(); + TokenNode op = (TokenNode) stack.pop(); + temp.addChild(ae); + temp.addChild(op); + temp.addChild(mep); + temp = ae; + } + temp.addChild((MulExp) stack.pop()); + } + } + + public boolean isAddOp() { + TokenType t = getCurrToken().getType(); + return t == TokenType.PLUS || t == TokenType.MINU; + } + + public int getType() { + if (getChildren().size() == 1) { + return ((MulExp) getChild(0)).getType(); + } else { + return ((AddExp) getChild(0)).getType() + | ((MulExp) getChild(2)).getType(); + } + } + + public int getValue() { + if (getChild(0) instanceof MulExp) { + return ((MulExp) getChild(0)).getValue(); + } else { + int left = ((AddExp) getChild(0)).getValue(); + int right = ((MulExp) getChild(2)).getValue(); + if (((TokenNode) getChild(1)).getType() == TokenType.PLUS) { + return left + right; + } else { + return left - right; + } + } + } +} diff --git a/frontend/ast/exp/Cond.java b/frontend/ast/exp/Cond.java new file mode 100644 index 0000000..3ddff91 --- /dev/null +++ b/frontend/ast/exp/Cond.java @@ -0,0 +1,18 @@ +package frontend.ast.exp; + +import frontend.ast.SyntaxType; +import error.Errors; +import frontend.lexer.TokenStream; +import frontend.ast.Node; + +public class Cond extends Node { + public Cond(TokenStream ts) { + super(SyntaxType.COND_EXP, ts); + } + + public void parse(Errors errors) { + LOrExp lep = new LOrExp(this.ts); + lep.parse(errors); + addChild(lep); + } +} diff --git a/frontend/ast/exp/ConstExp.java b/frontend/ast/exp/ConstExp.java new file mode 100644 index 0000000..c83a048 --- /dev/null +++ b/frontend/ast/exp/ConstExp.java @@ -0,0 +1,22 @@ +package frontend.ast.exp; + +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; + +public class ConstExp extends Node { + public ConstExp(TokenStream ts) { + super(SyntaxType.CONST_EXP, ts); + } + + public void parse(Errors errors) { + AddExp ade = new AddExp(ts); + ade.parse(errors); + addChild(ade); + } + + public int getValue() { + return ((AddExp) getChild(0)).getValue(); + } +} diff --git a/frontend/ast/exp/EqExp.java b/frontend/ast/exp/EqExp.java new file mode 100644 index 0000000..2d36914 --- /dev/null +++ b/frontend/ast/exp/EqExp.java @@ -0,0 +1,49 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.NodeStack; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import error.Errors; + +public class EqExp extends Node { + public EqExp(TokenStream ts) { + super(SyntaxType.EQ_EXP, ts); + } + + public void parse(Errors errors) { + NodeStack stack = new NodeStack(); + while (true) { + RelExp relexp = new RelExp(this.ts); + relexp.parse(errors); + stack.push(relexp); + if (isEqOp()) { + stack.push(new TokenNode(ts)); // eqop + } else { + break; + } + } + if(stack.size() == 1) { + this.addChild((RelExp)stack.pop()); + } else { + EqExp temp = this; + while (stack.size() > 1) { + EqExp eep = new EqExp(this.ts); + RelExp relexp = (RelExp)stack.pop(); + TokenNode eqop = (TokenNode)stack.pop(); + temp.addChild(eep); + temp.addChild(eqop); + temp.addChild(relexp); + temp = eep; + } + temp.addChild((RelExp)stack.pop()); + } + } + + public boolean isEqOp() { + TokenType t = getCurrToken().getType(); + return t == TokenType.EQL || t == TokenType.NEQ; + } +} diff --git a/frontend/ast/exp/Exp.java b/frontend/ast/exp/Exp.java new file mode 100644 index 0000000..2e58845 --- /dev/null +++ b/frontend/ast/exp/Exp.java @@ -0,0 +1,27 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import midend.symbol.SymbolManager; +import error.Errors; + +public class Exp extends Node { + public Exp(TokenStream ts) { + super(SyntaxType.EXP, ts); + } + + public void parse(Errors errors) { + AddExp addexp = new AddExp(this.ts); + addexp.parse(errors); + addChild(addexp); + } + + public int getType() { + return ((AddExp) getChild(0)).getType(); + } + + public int getValue() { + return ((AddExp) getChild(0)).getValue(); + } +} diff --git a/frontend/ast/exp/LAndExp.java b/frontend/ast/exp/LAndExp.java new file mode 100644 index 0000000..9759ef0 --- /dev/null +++ b/frontend/ast/exp/LAndExp.java @@ -0,0 +1,44 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.NodeStack; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import error.Errors; + +public class LAndExp extends Node { + public LAndExp(TokenStream ts) { + super(SyntaxType.LAND_EXP, ts); + } + + public void parse(Errors errors) { + NodeStack stack = new NodeStack(); + while (true) { + EqExp eep = new EqExp(this.ts); + eep.parse(errors); + stack.push(eep); + if (getCurrToken().getType() == TokenType.AND) { + stack.push(new TokenNode(ts)); // landop + } else { + break; + } + } + if (stack.size() == 1) { + this.addChild((EqExp)stack.pop()); + } else { + LAndExp temp = this; + while(stack.size() > 1) { + LAndExp lae = new LAndExp(this.ts); + EqExp eep = (EqExp)stack.pop(); + TokenNode landop = (TokenNode)stack.pop(); + temp.addChild(lae); + temp.addChild(landop); + temp.addChild(eep); + temp = lae; + } + temp.addChild((EqExp)stack.pop()); + } + } +} diff --git a/frontend/ast/exp/LOrExp.java b/frontend/ast/exp/LOrExp.java new file mode 100644 index 0000000..d4e80af --- /dev/null +++ b/frontend/ast/exp/LOrExp.java @@ -0,0 +1,44 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.NodeStack; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import error.Errors; + +public class LOrExp extends Node { + public LOrExp(TokenStream ts) { + super(SyntaxType.LOR_EXP, ts); + } + + public void parse(Errors errors) { + NodeStack stack = new NodeStack(); + while (true) { + LAndExp andexp = new LAndExp(this.ts); + andexp.parse(errors); + stack.push(andexp); + if (getCurrToken().getType() == TokenType.OR) { + stack.push(new TokenNode(ts)); // lorop + } else { + break; + } + } + if (stack.size() == 1) { + this.addChild((LAndExp)stack.pop()); + } else { + LOrExp temp = this; + while(stack.size() > 1) { + LOrExp loe = new LOrExp(this.ts); + LAndExp lae = (LAndExp)stack.pop(); + TokenNode lorop = (TokenNode)stack.pop(); + temp.addChild(loe); + temp.addChild(lorop); + temp.addChild(lae); + temp = loe; + } + temp.addChild((LAndExp)stack.pop()); + } + } +} diff --git a/frontend/ast/exp/LVal.java b/frontend/ast/exp/LVal.java new file mode 100644 index 0000000..51fd790 --- /dev/null +++ b/frontend/ast/exp/LVal.java @@ -0,0 +1,59 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import midend.symbol.SymbolManager; +import midend.symbol.Symbol; +import midend.symbol.ArraySymbol; +import error.Errors; +import error.Error; +import error.ErrorType; + +public class LVal extends Node { + public LVal(TokenStream ts) { + super(SyntaxType.LVAL_EXP, ts); + } + + public void parse(Errors errors) { + addChild(new TokenNode(this.ts)); // idenfr + if (getCurrToken().getType() == TokenType.LBRACK) { + addChild(new TokenNode(this.ts)); // lbrack + Exp exp = new Exp(this.ts); + exp.parse(errors); + addChild(exp); + if (getCurrToken().getType() == TokenType.RBRACK) { + addChild(new TokenNode(this.ts)); // rbrack + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.k)); + } + } + } + + public int getType() { + if (getChildren().size() == 1) { + TokenNode idenfr = (TokenNode) getChild(0); + Symbol symbol = SymbolManager.getSymbol(idenfr.getName()); + if (symbol instanceof ArraySymbol) { + return 1; + } + return 0; + } else { + return 0; + } + } + + public int getValue() { + TokenNode idenfr = (TokenNode) getChild(0); //idenfr一定是个常量,可在符号表找到且有值 + if (getChildren().size() == 1) { + Symbol symbol = SymbolManager.getSymbol(idenfr.getName()); + return symbol.getValue(0); + } else { + int index = ((Exp) getChild(2)).getValue(); + Symbol symbol = SymbolManager.getSymbol(idenfr.getName()); + return symbol.getValue(index); + } + } +} diff --git a/frontend/ast/exp/MulExp.java b/frontend/ast/exp/MulExp.java new file mode 100644 index 0000000..96f0aeb --- /dev/null +++ b/frontend/ast/exp/MulExp.java @@ -0,0 +1,75 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import frontend.ast.NodeStack; +import midend.symbol.SymbolManager; +import error.Errors; + +public class MulExp extends Node { + public MulExp(TokenStream ts) { + super(SyntaxType.MUL_EXP, ts); + } + + public void parse(Errors errors) { + NodeStack stack = new NodeStack(); + while (true) { + UnaryExp uep = new UnaryExp(this.ts); + uep.parse(errors); + stack.push(uep); + if (isMulOp()) { + stack.push(new TokenNode(ts)); // mulop + } else { + break; + } + } + if (stack.size() == 1) { + addChild((UnaryExp)stack.pop()); + } else { + MulExp temp = this; + while (stack.size() > 1) { + MulExp mep = new MulExp(this.ts); + UnaryExp uep = (UnaryExp) stack.pop(); + TokenNode mulop = (TokenNode) stack.pop(); + temp.addChild(mep); + temp.addChild(mulop); + temp.addChild(uep); + temp = mep; + } + temp.addChild((UnaryExp)stack.pop()); + } + } + + public boolean isMulOp() { + TokenType t = getCurrToken().getType(); + return t == TokenType.MULT || t == TokenType.DIV || t == TokenType.MOD; + } + + public int getType() { + if (getChildren().size() == 1) { + return ((UnaryExp) getChild(0)).getType(); + } else { + return ((MulExp) getChild(0)).getType() + | ((UnaryExp) getChild(2)).getType(); + } + } + + public int getValue() { + if (getChild(0) instanceof UnaryExp) { + return ((UnaryExp) getChild(0)).getValue(); + } else { + int left = ((MulExp) getChild(0)).getValue(); + int right = ((UnaryExp) getChild(2)).getValue(); + if (((TokenNode) getChild(1)).getType() == TokenType.MULT) { + return left * right; + } else if (((TokenNode) getChild(1)).getType() == TokenType.DIV) { + return left / right; + } else { + return left % right; + } + } + } +} diff --git a/frontend/ast/exp/NumberExp.java b/frontend/ast/exp/NumberExp.java new file mode 100644 index 0000000..12b93af --- /dev/null +++ b/frontend/ast/exp/NumberExp.java @@ -0,0 +1,21 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import error.Errors; +import frontend.ast.token.TokenNode; + +public class NumberExp extends Node { + public NumberExp(TokenStream ts) { + super(SyntaxType.NUMBER, ts); + } + + public void parse(Errors errors) { + addChild(new TokenNode(ts)); //intconst + } + + public int getValue() { + return Integer.parseInt(((TokenNode) getChild(0)).getValue()); + } +} diff --git a/frontend/ast/exp/PrimaryExp.java b/frontend/ast/exp/PrimaryExp.java new file mode 100644 index 0000000..9934797 --- /dev/null +++ b/frontend/ast/exp/PrimaryExp.java @@ -0,0 +1,58 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import error.Errors; +import error.Error; +import error.ErrorType; + +public class PrimaryExp extends Node { + public PrimaryExp(TokenStream ts) { + super(SyntaxType.PRIMARY_EXP, ts); + } + + public void parse(Errors errors) { + if (getCurrToken().getType() == TokenType.LPARENT) { + addChild(new TokenNode(ts)); // lparent + Exp exp = new Exp(this.ts); + exp.parse(errors); + addChild(exp); + if (getCurrToken().getType() == TokenType.RPARENT) { + addChild(new TokenNode(ts)); // rparent + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.j)); + } + } else if (getCurrToken().getType() == TokenType.IDENFR) { + LVal lval = new LVal(this.ts); + lval.parse(errors); + addChild(lval); + } else { + NumberExp num = new NumberExp(this.ts); + num.parse(errors); + addChild(num); + } + } + + public int getType() { + if (getChild(0) instanceof TokenNode) { + return ((Exp) getChild(1)).getType(); + } else if (getChild(0) instanceof LVal) { + return ((LVal) getChild(0)).getType(); + } else { + return 0; + } + } + + public int getValue() { + if (getChild(0) instanceof TokenNode) { + return ((Exp) getChild(1)).getValue(); + } else if (getChild(0) instanceof LVal) { + return ((LVal) getChild(0)).getValue(); + } else { + return ((NumberExp) getChild(0)).getValue(); + } + } +} diff --git a/frontend/ast/exp/RelExp.java b/frontend/ast/exp/RelExp.java new file mode 100644 index 0000000..4d244f5 --- /dev/null +++ b/frontend/ast/exp/RelExp.java @@ -0,0 +1,50 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.NodeStack; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import error.Errors; + +public class RelExp extends Node { + public RelExp(TokenStream ts) { + super(SyntaxType.REL_EXP, ts); + } + + public void parse(Errors errors) { + NodeStack stack = new NodeStack(); + while (true) { + AddExp addexp = new AddExp(this.ts); + addexp.parse(errors); + stack.push(addexp); + if (isRelOp()) { + stack.push(new TokenNode(ts)); // relop + } else { + break; + } + } + if (stack.size() == 1) { + this.addChild((AddExp)stack.pop()); + } else { + RelExp temp = this; + while(stack.size() > 1) { + RelExp rexp = new RelExp(this.ts); + AddExp addexp = (AddExp)stack.pop(); + TokenNode relop = (TokenNode)stack.pop(); + temp.addChild(rexp); + temp.addChild(relop); + temp.addChild(addexp); + temp = rexp; + } + temp.addChild((AddExp)stack.pop()); + } + } + + public boolean isRelOp() { + TokenType t = getCurrToken().getType(); + return t == TokenType.LSS || t == TokenType.GRE + || t == TokenType.LEQ || t == TokenType.GEQ; + } +} diff --git a/frontend/ast/exp/UnaryExp.java b/frontend/ast/exp/UnaryExp.java new file mode 100644 index 0000000..bd5f3a7 --- /dev/null +++ b/frontend/ast/exp/UnaryExp.java @@ -0,0 +1,124 @@ +package frontend.ast.exp; + +import java.util.ArrayList; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import frontend.ast.func.FuncRParams; +import midend.symbol.FuncSymbol; +import midend.symbol.SymbolManager; +import error.Errors; + +import error.Error; +import error.ErrorType; + +public class UnaryExp extends Node { + public UnaryExp(TokenStream ts) { + super(SyntaxType.UNARY_EXP, ts); + } + + public void parse(Errors errors) { + if (isUnaryOp()) { + UnaryOp uop = new UnaryOp(ts); + uop.parse(errors); + addChild(uop); + UnaryExp uep = new UnaryExp(ts); + uep.parse(errors); + addChild(uep); + } else if (getCurrToken().getType() == TokenType.IDENFR + && this.ts.peek(1).getType() == TokenType.LPARENT) { + addChild(new TokenNode(ts)); // idenfr + addChild(new TokenNode(ts)); // lparent + if (isExp()) { + FuncRParams frp = new FuncRParams(ts); + frp.parse(errors); + addChild(frp); + } + if (getCurrToken().getType() == TokenType.RPARENT) { + addChild(new TokenNode(ts)); // rparent + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.j)); + } + } else { + PrimaryExp pme = new PrimaryExp(ts); + pme.parse(errors); + addChild(pme); + } + } + + public boolean isUnaryOp() { + return getCurrToken().getType() == TokenType.PLUS + || getCurrToken().getType() == TokenType.MINU + || getCurrToken().getType() == TokenType.NOT; + } + + public boolean isExp() { + TokenType t = getCurrToken().getType(); + return t == TokenType.PLUS || t == TokenType.MINU || t == TokenType.NOT + || t == TokenType.IDENFR || t == TokenType.LPARENT || t == TokenType.INTCON; + } + + public void handleFuncCall(Errors errors) { // 当其为函数调用形式时才会调用 + TokenNode funcIdenfr = (TokenNode) getChild(0); + if (funcIdenfr.getName().equals("getint")) { + if (getChildren().size() == 4) { + errors.addError(new Error(funcIdenfr.getLine(), ErrorType.d)); + } + return; + } + FuncSymbol funcSymbol = (FuncSymbol) SymbolManager.getSymbol(funcIdenfr.getName()); + if (funcSymbol == null) { + errors.addError(new Error(funcIdenfr.getLine(), ErrorType.c)); + return; + } + int fparaNum = funcSymbol.getParamNum(); + int rparaNum = 0; + if (getChildren().size() >= 3 && getChild(2) instanceof FuncRParams) { + FuncRParams frp = (FuncRParams) getChild(2); + rparaNum = frp.getParamNum(); + if (rparaNum == fparaNum) { + frp.checkParamType(funcSymbol, errors, funcIdenfr.getLine()); + } + } + if (fparaNum != rparaNum) { + errors.addError(new Error(funcIdenfr.getLine(), ErrorType.d)); + } + } + + public int getType() { + if (getChild(0) instanceof PrimaryExp) { + return ((PrimaryExp) getChild(0)).getType(); + } else if (getChild(0) instanceof TokenNode) { + return 0; + } else { + return ((UnaryExp) getChild(1)).getType(); + } + } + + public int getValue() { + if (getChild(0) instanceof UnaryOp) { + UnaryOp uop = (UnaryOp) getChild(0); + TokenNode opToken = (TokenNode) uop.getChild(0); + return opToken.getType() == TokenType.PLUS ? ((UnaryExp) getChild(1)).getValue() + : -((UnaryExp) getChild(1)).getValue(); + } else if (getChild(0) instanceof PrimaryExp) { + return ((PrimaryExp) getChild(0)).getValue(); + } else { + return 0; // 0表示这个是函数,getvalue只是对于常量或常量表达式取值,所以正常情况调用getvalue函数时是不会跳转到这个分支的 + } + } + + public ArrayList getParamList() { + if (!(getChild(0) instanceof TokenNode)) { + return null; + } else { + if (getChildren().size() >= 3 && (getChild(2) instanceof FuncRParams)) { + return ((FuncRParams) getChild(2)).getParamList(); + } + return new ArrayList(); + } + } +} diff --git a/frontend/ast/exp/UnaryOp.java b/frontend/ast/exp/UnaryOp.java new file mode 100644 index 0000000..b5931ff --- /dev/null +++ b/frontend/ast/exp/UnaryOp.java @@ -0,0 +1,17 @@ +package frontend.ast.exp; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import error.Errors; +import frontend.ast.token.TokenNode; + +public class UnaryOp extends Node { + public UnaryOp(TokenStream ts) { + super(SyntaxType.UNARY_OP, ts); + } + + public void parse(Errors errors) { + addChild(new TokenNode(ts)); // unary op + } +} diff --git a/frontend/ast/func/FuncDef.java b/frontend/ast/func/FuncDef.java new file mode 100644 index 0000000..569ec19 --- /dev/null +++ b/frontend/ast/func/FuncDef.java @@ -0,0 +1,108 @@ +package frontend.ast.func; + +import java.util.ArrayList; + +import error.Error; +import error.ErrorType; +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.block.Block; +import frontend.ast.block.BlockItem; +import frontend.ast.decl.Decl; +import midend.symbol.Symbol; +import midend.symbol.SymbolType; +import midend.symbol.FuncSymbol; +import midend.symbol.ArraySymbol; +import midend.symbol.SymbolManager; + +public class FuncDef extends Node { + public FuncDef(TokenStream ts) { + super(SyntaxType.FUNC_DEF, ts); + } + + public void parse(Errors errors) { + FuncType ft = new FuncType(this.ts); + ft.parse(errors); + addChild(ft); + TokenNode ident = new TokenNode(this.ts); + addChild(ident); + TokenNode lparen = new TokenNode(this.ts); + addChild(lparen); + if (getCurrToken().getType() != TokenType.RPARENT && + getCurrToken().getType() != TokenType.LBRACE) { + FuncFParams ffp = new FuncFParams(this.ts); + ffp.parse(errors); + addChild(ffp); + if (getCurrToken().getType() == TokenType.RPARENT) { + TokenNode rparen = new TokenNode(this.ts); + addChild(rparen); + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.j)); + } + } else if (getCurrToken().getType() == TokenType.LBRACE) { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.j)); + } else { + TokenNode rparen = new TokenNode(this.ts); + addChild(rparen); + } + Block block = new Block(this.ts); + block.setIsFuncBlock(true); + block.parse(errors); + addChild(block); + } + + public Symbol getSymbol() { + if (((FuncType) getChild(0)).isVoid()) { + TokenNode tn = (TokenNode) getChild(1); + return new FuncSymbol(tn.getName(), + SymbolType.VOID_FUNC, tn.getLine(), 0); + } else { + TokenNode tn = (TokenNode) getChild(1); + return new FuncSymbol(tn.getName(), + SymbolType.INT_FUNC, tn.getLine(), 1); + } + } + + public void addParamSymbol(Symbol funcSymbol, Errors errors) { + if (getChild(3) instanceof FuncFParams) { + FuncFParams ffp = (FuncFParams) getChild(3); + ArrayList paramList = ffp.getParamList(); + for (FuncFParam param : paramList) { + Symbol paramSymbol = param.getSymbol(); + SymbolManager.addSymbol(paramSymbol, errors); + ((FuncSymbol) funcSymbol).addParamSymbol(paramSymbol); // 将形参存到函数的符号中 + if (paramSymbol instanceof ArraySymbol) { + ((FuncSymbol) funcSymbol).addParam(1); + } else { + ((FuncSymbol) funcSymbol).addParam(0); + } + } + } + } + + public void checkReturnNode(Errors errors) { + Block block = (Block) getChild(getChildren().size() - 1); + TokenNode rbrace = (TokenNode) block.getChild(block.getChildren().size() - 1); + if (block.getChildren().size() == 2) { + errors.addError(new Error(rbrace.getLine(), ErrorType.g)); + } else { + BlockItem bit = (BlockItem) block.getChild(block.getChildren().size() - 2); + if (bit.getChild(0) instanceof Decl) { + errors.addError(new Error(rbrace.getLine(), ErrorType.g)); + } else { + if (!(bit.getChild(0).getChild(0) instanceof TokenNode)) { + errors.addError(new Error(rbrace.getLine(), ErrorType.g)); + } else { + TokenNode returnNode = (TokenNode) bit.getChild(0).getChild(0); + if (returnNode.getType() != TokenType.RETURNTK) { + errors.addError(new Error(rbrace.getLine(), ErrorType.g)); + } + } + } + } + } +} diff --git a/frontend/ast/func/FuncFParam.java b/frontend/ast/func/FuncFParam.java new file mode 100644 index 0000000..18e9929 --- /dev/null +++ b/frontend/ast/func/FuncFParam.java @@ -0,0 +1,49 @@ +package frontend.ast.func; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; + +import midend.symbol.Symbol; +import midend.symbol.SymbolType; +import midend.symbol.ArraySymbol; + +import error.Errors; +import frontend.ast.token.TokenNode; +import error.ErrorType; +import error.Error; + +public class FuncFParam extends Node { + public FuncFParam(TokenStream ts) { + super(SyntaxType.FUNC_FORMAL_PARAM, ts); + } + + public void parse(Errors errors) { + TokenNode intkk = new TokenNode(this.ts); + addChild(intkk); + TokenNode ident = new TokenNode(this.ts); + addChild(ident); + if (getCurrToken().getType() == TokenType.LBRACK) { + TokenNode lbrack = new TokenNode(this.ts); + addChild(lbrack); + if (getCurrToken().getType() == TokenType.RBRACK) { + TokenNode rbrack = new TokenNode(this.ts); + addChild(rbrack); + } else { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.k)); + } + } + } + + public Symbol getSymbol() { + if (getChildren().size() == 2) { + TokenNode tn = (TokenNode) getChild(1); + return new Symbol(tn.getName(), SymbolType.INT, tn.getLine()); + } else { + TokenNode tn = (TokenNode) getChild(1); + return new ArraySymbol(tn.getName(), SymbolType.INT_ARRAY, tn.getLine(), -1); + //这里不求维数,因为函数形参为数组只是相当于一个指针 + } + } +} \ No newline at end of file diff --git a/frontend/ast/func/FuncFParams.java b/frontend/ast/func/FuncFParams.java new file mode 100644 index 0000000..39b19fa --- /dev/null +++ b/frontend/ast/func/FuncFParams.java @@ -0,0 +1,38 @@ +package frontend.ast.func; + +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; + +import java.util.ArrayList; + +public class FuncFParams extends Node { + public FuncFParams(TokenStream ts) { + super(SyntaxType.FUNC_FORMAL_PARAM_S, ts); + } + + public void parse(Errors errors) { + while (true) { + FuncFParam ffp = new FuncFParam(this.ts); + ffp.parse(errors); + addChild(ffp); + if (getCurrToken().getType() == TokenType.COMMA) { + TokenNode comma = new TokenNode(this.ts); + addChild(comma); + } else { + break; + } + } + } + + public ArrayList getParamList() { + ArrayList paramList = new ArrayList<>(); + for (int i = 0; i < getChildren().size(); i += 2) { + paramList.add((FuncFParam) getChild(i)); + } + return paramList; + } +} diff --git a/frontend/ast/func/FuncRParams.java b/frontend/ast/func/FuncRParams.java new file mode 100644 index 0000000..9839bbf --- /dev/null +++ b/frontend/ast/func/FuncRParams.java @@ -0,0 +1,57 @@ +package frontend.ast.func; + +import java.util.ArrayList; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import error.Errors; +import error.Error; +import error.ErrorType; +import frontend.ast.token.TokenNode; +import frontend.ast.exp.Exp; +import midend.symbol.FuncSymbol; + +public class FuncRParams extends Node { + public FuncRParams(TokenStream ts) { + super(SyntaxType.FUNC_REAL_PARAM_S, ts); + } + + public void parse(Errors errors) { + while (true) { + Exp ep = new Exp(ts); + ep.parse(errors); + addChild(ep); + if (getCurrToken().getType() == TokenType.COMMA) { + addChild(new TokenNode(ts)); // comma + } else { + break; + } + } + } + + public int getParamNum() { + return (getChildren().size() + 1) / 2; + } + + public void checkParamType(FuncSymbol funcSymbol, Errors errors, int line) { + int fparaNum = funcSymbol.getParamNum(); + int rparaNum = getParamNum(); + int size = rparaNum < fparaNum ? rparaNum : fparaNum; + for (int i = 0; i < size; i++) { + Exp exp = (Exp) getChild(i * 2); + if (exp.getType() != funcSymbol.getParamType(i)) { + errors.addError(new Error(line, ErrorType.e)); + } + } + } + + public ArrayList getParamList() { + ArrayList paramList = new ArrayList(); + for (int i = 0; i < getChildren().size(); i += 2) { + paramList.add((Exp) getChild(i)); + } + return paramList; + } +} diff --git a/frontend/ast/func/FuncType.java b/frontend/ast/func/FuncType.java new file mode 100644 index 0000000..b34a180 --- /dev/null +++ b/frontend/ast/func/FuncType.java @@ -0,0 +1,27 @@ +package frontend.ast.func; + +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; + +public class FuncType extends Node { + public FuncType(TokenStream ts) { + super(SyntaxType.FUNC_TYPE, ts); + } + + public void parse(Errors errors) { + TokenNode ident = new TokenNode(this.ts); + addChild(ident); + } + + public boolean isVoid() { + return ((TokenNode) getChild(0)).getType() == TokenType.VOIDTK; + } + + public boolean isInt() { + return ((TokenNode) getChild(0)).getType() == TokenType.INTTK; + } +} diff --git a/frontend/ast/func/MainFuncDef.java b/frontend/ast/func/MainFuncDef.java new file mode 100644 index 0000000..322c0aa --- /dev/null +++ b/frontend/ast/func/MainFuncDef.java @@ -0,0 +1,60 @@ +package frontend.ast.func; + +import error.ErrorType; +import error.Errors; +import error.Error; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.ast.block.BlockItem; +import frontend.ast.decl.Decl; +import frontend.lexer.TokenStream; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenType; +import frontend.ast.block.Block; + +public class MainFuncDef extends Node { + public MainFuncDef(TokenStream ts) { + super(SyntaxType.MAIN_FUNC_DEF, ts); + } + + public void parse(Errors errors) { + TokenNode intkk = new TokenNode(this.ts); + addChild(intkk); + TokenNode mainkk = new TokenNode(this.ts); + addChild(mainkk); + TokenNode lparent = new TokenNode(this.ts); + addChild(lparent); + if (getCurrToken().getType() != TokenType.RPARENT) { + errors.addError(new Error(this.ts.peek(-1).getLine(), ErrorType.j)); + } else { + TokenNode rparent = new TokenNode(this.ts); + addChild(rparent); + } + Block block = new Block(this.ts); + block.setIsFuncBlock(true); + block.parse(errors); + addChild(block); + } + + public void checkReturnNode(Errors errors) { + Block block = (Block) getChild(getChildren().size() - 1); + TokenNode rbrace = (TokenNode) block.getChild(block.getChildren().size() - 1); + if (block.getChildren().size() == 2) { + errors.addError(new Error(rbrace.getLine(), ErrorType.g)); + } else { + BlockItem bit = (BlockItem) block.getChild(block.getChildren().size() - 2); + if (bit.getChild(0) instanceof Decl) { + errors.addError(new Error(rbrace.getLine(), ErrorType.g)); + } else { + if (!(bit.getChild(0).getChild(0) instanceof TokenNode)) { + errors.addError(new Error(rbrace.getLine(), ErrorType.g)); + } else { + TokenNode returnNode = (TokenNode) bit.getChild(0).getChild(0); + if (returnNode.getType() != TokenType.RETURNTK) { + errors.addError(new Error(rbrace.getLine(), ErrorType.g)); + } + } + } + } + } +} diff --git a/frontend/ast/token/TokenNode.java b/frontend/ast/token/TokenNode.java new file mode 100644 index 0000000..dd28af3 --- /dev/null +++ b/frontend/ast/token/TokenNode.java @@ -0,0 +1,50 @@ +package frontend.ast.token; + +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.Token; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; + +public class TokenNode extends Node { + private Token token; + + public TokenNode(TokenStream ts) { + super(SyntaxType.TOKEN, ts); + token = ts.read(); + } + + @Override + public String toString() { + return token.toString(); + } + + public String getValue() { + return token.getValue(); + } + + public int getLine() { + return token.getLine(); + } + + public String getName() { + return token.getValue(); + } + + public TokenType getType() { + return token.getType(); + } + + public int getFormatNum() { + int num = 0; + String str = token.getValue(); + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == '%' && i + 1 < str.length() + && str.charAt(i + 1) == 'd') { + num++; + i++; + } + } + return num; + } +} diff --git a/frontend/ast/val/ConstInitVal.java b/frontend/ast/val/ConstInitVal.java new file mode 100644 index 0000000..6bb841a --- /dev/null +++ b/frontend/ast/val/ConstInitVal.java @@ -0,0 +1,58 @@ +package frontend.ast.val; + +import java.util.ArrayList; + +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.ast.exp.ConstExp; +import frontend.ast.token.TokenNode; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; + +public class ConstInitVal extends Node { + public ConstInitVal(TokenStream ts) { + super(SyntaxType.CONST_INIT_VAL, ts); + } + + public void parse(Errors errors) { + if (getCurrToken().getType() != TokenType.LBRACE) { + ConstExp cep = new ConstExp(this.ts); + cep.parse(errors); + addChild(cep); + } else { + TokenNode lbrace = new TokenNode(this.ts); + addChild(lbrace); + if (getCurrToken().getType() != TokenType.RBRACE) { + while (true) { // judge rbrace or not ?? + ConstExp cep = new ConstExp(this.ts); + cep.parse(errors); + addChild(cep); + if (getCurrToken().getType() == TokenType.COMMA) { + TokenNode comma = new TokenNode(this.ts); + addChild(comma); + } else { + break; + } + } + } + TokenNode rbrace = new TokenNode(this.ts); + addChild(rbrace); + } + } + + public ArrayList getValue() { + ArrayList valueList = new ArrayList<>(); + if (getChild(0) instanceof ConstExp) { + valueList.add(((ConstExp) getChild(0)).getValue()); + return valueList; + } else { + for (int i = 1; i < getChildren().size(); i += 2) { + if (getChild(i) instanceof ConstExp) { + valueList.add(((ConstExp) getChild(i)).getValue()); + } + } + return valueList; + } + } +} diff --git a/frontend/ast/val/InitVal.java b/frontend/ast/val/InitVal.java new file mode 100644 index 0000000..d3f39aa --- /dev/null +++ b/frontend/ast/val/InitVal.java @@ -0,0 +1,71 @@ +package frontend.ast.val; + +import java.util.ArrayList; + +import error.Errors; +import frontend.ast.Node; +import frontend.ast.SyntaxType; +import frontend.lexer.TokenStream; +import frontend.lexer.TokenType; +import frontend.ast.token.TokenNode; +import frontend.ast.exp.Exp; + +public class InitVal extends Node { + public InitVal(TokenStream ts) { + super(SyntaxType.INIT_VAL, ts); + } + + public void parse(Errors errors) { + if (getCurrToken().getType() == TokenType.LBRACE) { + TokenNode lbrace = new TokenNode(this.ts); + addChild(lbrace); + if (getCurrToken().getType() != TokenType.RBRACE) { + while (true) { + Exp ep = new Exp(this.ts); + ep.parse(errors); + addChild(ep); + if (getCurrToken().getType() == TokenType.COMMA) { + TokenNode comma = new TokenNode(this.ts); + addChild(comma); + } else { + break; + } + } + } + TokenNode rbrace = new TokenNode(this.ts); + addChild(rbrace); + } else { + Exp ep = new Exp(this.ts); + ep.parse(errors); + addChild(ep); + } + } + + public ArrayList getValue() { + ArrayList values = new ArrayList<>(); + if (getChild(0) instanceof Exp) { + values.add(((Exp) getChild(0)).getValue()); + } else { + for (int i = 1; i < getChildren().size(); i += 2) { + if (getChild(i) instanceof Exp) { + values.add(((Exp) getChild(i)).getValue()); + } + } + } + return values; + } + + public ArrayList getExpList() { + ArrayList expList = new ArrayList<>(); + if (getChild(0) instanceof Exp) { + expList.add((Exp) getChild(0)); + } else { + for (int i = 1; i < getChildren().size(); i += 2) { + if (getChild(i) instanceof Exp) { + expList.add((Exp) getChild(i)); + } + } + } + return expList; + } +} diff --git a/frontend/lexer/Lexer.java b/frontend/lexer/Lexer.java new file mode 100644 index 0000000..ac4b0d7 --- /dev/null +++ b/frontend/lexer/Lexer.java @@ -0,0 +1,245 @@ +package frontend.lexer; + +import java.util.ArrayList; + +import error.Error; +import error.ErrorType; +import error.Errors; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.io.IOException; + +public class Lexer { + private String input; + private ArrayList tokens; + private int position; + private int line; + private char currentChar; + + public Lexer(String input) { + this.input = input; + this.tokens = new ArrayList(); + this.position = 0; + this.line = 1; + } + + public void lex(Errors errors) { + int sigComment = 0; + while (this.position < this.input.length()) { + currentChar = this.input.charAt(this.position); + if (currentChar == ' ' || currentChar == '\t') { + this.position++; + continue; + } + if (currentChar == '\n' || currentChar == '\r') { + if (currentChar == '\r') { + if (this.position + 1 < this.input.length() && + this.input.charAt(this.position + 1) == '\n') { + this.position++; + } + } + this.line++; + this.position++; + if (sigComment == 1) { + sigComment = 0; + } + continue; + } + if (sigComment == 0) { + if (currentChar == '/') { + if (this.position + 1 < this.input.length() && + this.input.charAt(this.position + 1) == '/') { + sigComment = 1; + this.position += 2; + continue; + } + if (this.position + 1 < this.input.length() && + this.input.charAt(this.position + 1) == '*') { + sigComment = 2; + this.position += 2; + continue; + } + } + if (this.isIntCons()) { + lexInt(); + continue; + } + if (this.isStrCons()) { + lexStr(); + continue; + } + if (this.isIdenfr()) { + lexIdenfr(); + continue; + } + lexOp(errors); + } + if (sigComment == 2) { + if (this.position + 1 < this.input.length() && + this.currentChar == '*' && this.input.charAt(this.position + 1) == '/') { + sigComment = 0; + this.position += 2; + continue; + } + } + if (sigComment != 0) { + this.position++; + } + } + } + + public boolean isIntCons() { + return Character.isDigit(this.currentChar); + } + + public boolean isStrCons() { + return this.currentChar == '"'; + } + + public boolean isIdenfr() { + return Character.isLowerCase(this.currentChar) || Character.isUpperCase(this.currentChar) + || this.currentChar == '_'; + } + + public boolean isNotWp() { + return !Character.isWhitespace(this.currentChar); + } + + public boolean isOp() { + return !this.isIntCons() && !this.isStrCons() && !this.isIdenfr(); + } + + public void lexInt() { + StringBuilder sb = new StringBuilder(); + while (this.position < this.input.length() && this.isIntCons()) { + sb.append(this.currentChar); + this.position++; + updateCurrentChar(); + } + this.tokens.add(new Token(sb.toString(), this.line)); + } + + public void lexStr() { + StringBuilder sb = new StringBuilder(); + sb.append(this.currentChar); + this.position++; + updateCurrentChar(); + while (this.position < this.input.length() && this.currentChar != '"') { + sb.append(this.currentChar); + this.position++; + updateCurrentChar(); + } + if (this.position < this.input.length() && this.currentChar == '"') { + sb.append(this.currentChar); + this.position++; + } + this.tokens.add(new Token(sb.toString(), this.line)); + } + + public void lexIdenfr() { + StringBuilder sb = new StringBuilder(); + while (this.position < this.input.length() && (this.isIdenfr() || this.isIntCons())) { + sb.append(this.currentChar); + this.position++; + updateCurrentChar(); + } + this.tokens.add(new Token(sb.toString(), this.line)); + } + + public void lexOp(Errors errors) { + StringBuilder sb = new StringBuilder(); + if (this.currentChar == '/' && this.position + 1 < this.input.length() && + (this.input.charAt(this.position + 1) == '/' || + this.input.charAt(this.position + 1) == '*')) { + return; + } + sb.append(this.currentChar); + switch (this.currentChar) { + case '&': + readAnd(sb); + break; + case '|': + readOr(sb); + break; + case '<': + readEq(sb); + break; + case '>': + readEq(sb); + break; + case '=': + readEq(sb); + break; + case '!': + readEq(sb); + break; + default: + break; + } + this.position++; + if (sb.toString().equals("&") || sb.toString().equals("|")) { + errors.addError(new Error(this.line, ErrorType.a)); + } + this.tokens.add(new Token(sb.toString(), this.line)); + } + + public void readAnd(StringBuilder sb) { + if (this.position + 1 < this.input.length() && + this.input.charAt(this.position + 1) == '&') { + this.position++; + currentChar = this.input.charAt(this.position); + sb.append(currentChar); + } + } + + public void readOr(StringBuilder sb) { + if (this.position + 1 < this.input.length() && + this.input.charAt(this.position + 1) == '|') { + this.position++; + currentChar = this.input.charAt(this.position); + sb.append(currentChar); + } + } + + public void readEq(StringBuilder sb) { + if (this.position + 1 < this.input.length() && + this.input.charAt(this.position + 1) == '=') { + this.position++; + currentChar = this.input.charAt(this.position); + sb.append(currentChar); + } + } + + public void updateCurrentChar() { + if (this.position < this.input.length()) { + currentChar = this.input.charAt(this.position); + } + } + + public void printTokens() { + for (Token token : this.tokens) { + token.adjustType(); + System.out.println(token.getType() + " " + token.getValue() + " " + token.getLine()); + } + } + + public void writeToFile(String fileName) { + try { + StringBuilder sb = new StringBuilder(); + for (Token token : this.tokens) { + token.adjustType(); + sb.append(token.toString()); + } + Files.write(Paths.get(fileName), sb.toString().getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public ArrayList getTokens() { + for (Token token : this.tokens) { + token.adjustType(); + } + return this.tokens; + } +} diff --git a/frontend/lexer/Token.java b/frontend/lexer/Token.java new file mode 100644 index 0000000..6f2952c --- /dev/null +++ b/frontend/lexer/Token.java @@ -0,0 +1,42 @@ +package frontend.lexer; + +public class Token { + private TokenType type; + private String value; + private int line; + + public Token(String value, int line) { + this.value = value; + this.type = TokenType.isWhatType(value); + this.line = line; + } + + public void adjustType() { + if (this.type == TokenType.IDENFR) { + if (this.value.charAt(0) == '\"' && + this.value.charAt(this.value.length() - 1) == '\"') { + this.type = TokenType.STRCON; + } + String regex = "^\\d+$"; + if (this.value.matches(regex)) { + this.type = TokenType.INTCON; + } + } + } + + public String getValue() { + return this.value; + } + + public TokenType getType() { + return this.type; + } + + public int getLine() { + return this.line; + } + + public String toString() { + return this.type + " " + this.value + "\n"; + } +} diff --git a/frontend/lexer/TokenStream.java b/frontend/lexer/TokenStream.java new file mode 100644 index 0000000..082d39c --- /dev/null +++ b/frontend/lexer/TokenStream.java @@ -0,0 +1,42 @@ +package frontend.lexer; + +import java.util.ArrayList; + +public class TokenStream { + private ArrayList tokens; + private int currentIndex; + + public TokenStream(ArrayList tokens) { + this.tokens = tokens; + } + + public Token read() { + if (currentIndex < tokens.size()) { + return tokens.get(currentIndex++); + } else { + return null; + } + } + + public void recall() { + if (currentIndex > 0) { + currentIndex--; + } + } + + public int getCurrentIndex() { + return currentIndex; + } + + public void resetIndex(int index) { + currentIndex = index; + } + + public Token peek(int step) { + if (currentIndex + step < tokens.size()) { + return tokens.get(currentIndex + step); + } else { + return null; + } + } +} diff --git a/frontend/lexer/TokenType.java b/frontend/lexer/TokenType.java new file mode 100644 index 0000000..8cb8d5a --- /dev/null +++ b/frontend/lexer/TokenType.java @@ -0,0 +1,123 @@ +package frontend.lexer; + +public enum TokenType { + IDENFR, + INTCON, + STRCON, + CONSTTK, + INTTK, + STATICTK, + BREAKTK, + CONTINUETK, + IFTK, + MAINTK, + ELSETK, + NOT, + AND, + OR, + FORTK, + RETURNTK, + VOIDTK, + PLUS, + MINU, + PRINTFTK, + MULT, + DIV, + MOD, + LSS, + LEQ, + GRE, + GEQ, + EQL, + NEQ, + SEMICN, + COMMA, + LPARENT, + RPARENT, + LBRACK, + RBRACK, + LBRACE, + RBRACE, + ASSIGN; + + public static TokenType isWhatType(String str) { + switch (str) { + case "const": + return TokenType.CONSTTK; + case "int": + return TokenType.INTTK; + case "static": + return TokenType.STATICTK; + case "break": + return TokenType.BREAKTK; + case "continue": + return TokenType.CONTINUETK; + case "if": + return TokenType.IFTK; + case "main": + return TokenType.MAINTK; + case "else": + return TokenType.ELSETK; + case "!": + return TokenType.NOT; + case "&&": + return TokenType.AND; + case "&": + return TokenType.AND; + case "||": + return TokenType.OR; + case "|": + return TokenType.OR; + case "for": + return TokenType.FORTK; + case "return": + return TokenType.RETURNTK; + case "void": + return TokenType.VOIDTK; + case "+": + return TokenType.PLUS; + case "-": + return TokenType.MINU; + case "printf": + return TokenType.PRINTFTK; + case "*": + return TokenType.MULT; + case "/": + return TokenType.DIV; + case "%": + return TokenType.MOD; + case "<": + return TokenType.LSS; + case "<=": + return TokenType.LEQ; + case ">": + return TokenType.GRE; + case ">=": + return TokenType.GEQ; + case "==": + return TokenType.EQL; + case "!=": + return TokenType.NEQ; + case ";": + return TokenType.SEMICN; + case ",": + return TokenType.COMMA; + case "(": + return TokenType.LPARENT; + case ")": + return TokenType.RPARENT; + case "[": + return TokenType.LBRACK; + case "]": + return TokenType.RBRACK; + case "{": + return TokenType.LBRACE; + case "}": + return TokenType.RBRACE; + case "=": + return TokenType.ASSIGN; + default: + return TokenType.IDENFR; + } + } +} diff --git a/frontend/parser/Parser.java b/frontend/parser/Parser.java new file mode 100644 index 0000000..8a8cda6 --- /dev/null +++ b/frontend/parser/Parser.java @@ -0,0 +1,38 @@ +package frontend.parser; + +import frontend.ast.CompUnit; +import frontend.lexer.TokenStream; + +import java.nio.file.Files; + +import error.Errors; + +import java.nio.file.Paths; +import java.io.IOException; + +public class Parser { + private TokenStream ts; + private CompUnit compUnit; + + public Parser(TokenStream ts) { + this.ts = ts; + this.compUnit = new CompUnit(this.ts); + } + + public void parse(Errors errors) { + compUnit.parse(errors); + } + + public CompUnit getCompUnit() { + return compUnit; + } + + public void writeToFile(String fileName) { + try { + String info = this.compUnit.getInfo(); + Files.write(Paths.get(fileName), info.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/midend/Midend.java b/midend/Midend.java new file mode 100644 index 0000000..c6d0c15 --- /dev/null +++ b/midend/Midend.java @@ -0,0 +1,31 @@ +package midend; + +import java.nio.file.Files; +import java.nio.file.Paths; +import frontend.ast.CompUnit; +import midend.llvm.IrBuilder; +import midend.llvm.IrModule; +import midend.visit.Visitor; + +public class Midend { + private IrModule module; + private Visitor visitor; + + public Midend(CompUnit compUnit) { + this.module = new IrModule(); + this.visitor = new Visitor(compUnit); + } + + public void generateLLvmIr() { + IrBuilder.setCurrentModule(module); + visitor.visit(); + } + + public void writeToFile(String fileName) { + try { + Files.write(Paths.get(fileName), module.toString().getBytes()); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/midend/errorhandle/ErrorHandler.java b/midend/errorhandle/ErrorHandler.java new file mode 100644 index 0000000..a973d41 --- /dev/null +++ b/midend/errorhandle/ErrorHandler.java @@ -0,0 +1,32 @@ +package midend.errorhandle; + +import frontend.ast.CompUnit; + +import midend.symbol.SymbolManager; + +import error.Errors; + +import java.nio.file.Files; +import java.nio.file.Paths; + +public class ErrorHandler { + private CompUnit compUnit; + + public ErrorHandler(CompUnit compUnit) { + this.compUnit = compUnit; + SymbolManager.init(); + } + + public void visit(Errors errors) { + compUnit.fillSymbolTable(false, false, errors); + } + + public void writeToFile(String fileName) { + try { + String info = SymbolManager.getSymbolTableInfo(); + Files.write(Paths.get(fileName), info.getBytes()); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/midend/llvm/IrBuilder.java b/midend/llvm/IrBuilder.java new file mode 100644 index 0000000..f8f4de8 --- /dev/null +++ b/midend/llvm/IrBuilder.java @@ -0,0 +1,143 @@ +package midend.llvm; + +import java.util.HashMap; +import java.util.Stack; + +import midend.llvm.value.IrFuncValue; +import midend.llvm.value.IrBasicBlock; +import midend.llvm.value.IrLoop; +import midend.llvm.type.IrType; +import midend.llvm.constant.IrConstant; +import midend.llvm.value.IrGlobalValue; +import midend.llvm.constant.IrConstantStr; +import midend.llvm.instr.IrInstr; + +public class IrBuilder { + private static final String prebb = "b_"; + private static final String prestr = "@s_"; + private static final String prefunc = "@f_"; + private static final String preglobal = "@g_"; + private static final String prelocal = "%v_"; + + private static IrModule module = null; + private static IrFuncValue currentFunc = null; + private static IrBasicBlock currentBB = null; + private static int strId = 0; + private static int globalId = 0; + private static int bblockId = 0; + private static HashMap funcIdMap = new HashMap<>(); // func, localId + private static Stack loopStack = new Stack<>(); + + public static void setCurrentModule(IrModule module) { + IrBuilder.module = module; + } + + public static void addNewFunc(String name, IrType retType) { + IrFuncValue func = new IrFuncValue(geFuncName(name), retType); + module.addFunc(func); + funcIdMap.put(func, 0); + currentFunc = func; + IrBasicBlock entryBB = new IrBasicBlock(getBlockName(), func); + func.addBBlock(entryBB); + currentBB = entryBB; + } + + public static void addNewFunc(IrFuncValue func) { + module.addFunc(func); + funcIdMap.put(func, 0); + currentFunc = func; + IrBasicBlock entryBB = new IrBasicBlock(getBlockName(), func); + func.addBBlock(entryBB); + currentBB = entryBB; + } + + public static void addNewBB() { + IrBasicBlock bb = new IrBasicBlock(getBlockName(), currentFunc); + currentFunc.addBBlock(bb); + } + + public static void addNewBB(IrBasicBlock bb) { + currentFunc.addBBlock(bb); + } + + public static void setCurrentBBlock(IrBasicBlock bb) { + currentBB = bb; + } + + public static void addNewGlobal(IrType type, boolean isConstant, IrConstant initVal) { + IrGlobalValue global = new IrGlobalValue(type, getGlobalName(), isConstant, initVal); + module.addGlobalVar(global); + } + + public static void addNewGlobal(IrGlobalValue global) { + module.addGlobalVar(global); + } + + public static void addNewStr(String str) { + if (module.containStr(str)) { + return; + } + module.addStr(new IrConstantStr(str, getStrName())); + } + + public static void addNewStr(IrConstantStr str) { + module.addStr(str); + } + + public static void addInstr(IrInstr instr) { + currentBB.addInstr(instr); + instr.setBBlock(currentBB); + } + + public static String geFuncName(String name) { + return name.equals("main") ? "@main" : prefunc + name; + } + + public static String getBlockName() { + return prebb + bblockId++; + } + + public static String getStrName() { + return prestr + strId++; + } + + public static String getGlobalName() { + return preglobal + globalId++; + } + + public static String getLocalName() { + int id = funcIdMap.get(currentFunc); + funcIdMap.put(currentFunc, id + 1); + return prelocal + id; + } + + public static String getLocalName(IrFuncValue func) { + int id = funcIdMap.get(func); + funcIdMap.put(func, id + 1); + return prelocal + id; + } + + public static IrModule getCurrentModule() { + return module; + } + + public static IrFuncValue getCurrentFunc() { + return currentFunc; + } + + public static IrBasicBlock getCurrentBB() { + return currentBB; + } + + public static void pushLoop(IrLoop loop) { + loopStack.push(loop); + } + + public static IrLoop popLoop() { + return loopStack.pop(); + } + + public static IrLoop getCurrentLoop() { + return loopStack.peek(); + } +} diff --git a/midend/llvm/IrModule.java b/midend/llvm/IrModule.java new file mode 100644 index 0000000..e50f9ad --- /dev/null +++ b/midend/llvm/IrModule.java @@ -0,0 +1,100 @@ +package midend.llvm; + +import java.util.ArrayList; +import java.util.HashMap; + +import midend.llvm.constant.IrConstantStr; +import midend.llvm.value.IrFuncValue; +import midend.llvm.value.IrGlobalValue; +import midend.llvm.instr.GetIntInstr; +import midend.llvm.instr.PutChInstr; +import midend.llvm.instr.PutIntInstr; +import midend.llvm.instr.PutStrInstr; + +public class IrModule { + private ArrayList decls; + private HashMap strs; + private ArrayList globalVars; + private ArrayList funcs; + + public IrModule() { + decls = new ArrayList<>(); + strs = new HashMap<>(); + globalVars = new ArrayList<>(); + funcs = new ArrayList<>(); + decls.add(GetIntInstr.getIntDecl()); + decls.add(PutChInstr.putChDecl()); + decls.add(PutIntInstr.putIntDecl()); + decls.add(PutStrInstr.putStrDecl()); + } + + public ArrayList getDecls() { + return decls; + } + + public HashMap getStrs() { + return strs; + } + + public ArrayList getGlobalVars() { + return globalVars; + } + + public ArrayList getFuncs() { + return funcs; + } + + public void addFunc(IrFuncValue func) { + funcs.add(func); + } + + public void addStr(IrConstantStr str) { + if (strs.containsKey(str.getValue())) { + return; + } + strs.put(str.getValue(), str); + } + + public boolean containStr(String str) { + return strs.containsKey(str); + } + + public IrConstantStr getStr(String str) { + if (containStr(str)) { + return strs.get(str); + } + return null; + } + + public void addGlobalVar(IrGlobalValue globalVar) { + globalVars.add(globalVar); + } + + public IrFuncValue getMainFunc() { + for (IrFuncValue func : funcs) { + if (func.isMain()) { + return func; + } + } + return null; + } + + //TODO: toString()方法编写 + public String toString() { + StringBuilder sb = new StringBuilder(); + for (String decl : decls) { + sb.append(decl).append("\n"); + } + for (IrConstantStr str : strs.values()) { + sb.append(str.toString()).append("\n"); + } + for (IrGlobalValue globalVar : globalVars) { + sb.append(globalVar.toString()).append("\n"); + } + for (IrFuncValue func : funcs) { + sb.append(func.toString()).append("\n"); + } + // System.out.println(funcs.size()); + return sb.toString(); + } +} diff --git a/midend/llvm/constant/IrConstant.java b/midend/llvm/constant/IrConstant.java new file mode 100644 index 0000000..fabfbeb --- /dev/null +++ b/midend/llvm/constant/IrConstant.java @@ -0,0 +1,14 @@ +package midend.llvm.constant; + +import midend.llvm.value.IrValue; +import midend.llvm.type.IrType; + +public class IrConstant extends IrValue { + public IrConstant(IrType type, String name) { + super(type, name); + } + + public String toString() { + return ""; + } +} diff --git a/midend/llvm/constant/IrConstantArray.java b/midend/llvm/constant/IrConstantArray.java new file mode 100644 index 0000000..ca8318d --- /dev/null +++ b/midend/llvm/constant/IrConstantArray.java @@ -0,0 +1,47 @@ +package midend.llvm.constant; + +import java.util.ArrayList; + +import midend.llvm.type.IrInterType; +import midend.llvm.type.IrArrayType; + +public class IrConstantArray extends IrConstant { + private ArrayList elements; + private int size; + + public IrConstantArray(String name, ArrayList elements, int size) { + super(new IrArrayType(IrInterType.INT32, size), name); + this.elements = elements == null ? new ArrayList<>() : new ArrayList<>(elements); + this.size = size; + } + + public ArrayList getElements() { + return elements; + } + + public int getSize() { + return size; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getType().toString() + " "); + if (elements.size() == 0) { + sb.append("zeroinitializer"); + } else { + sb.append("["); + for (IrConstant element : elements) { + sb.append(element.toString()); + if (element != elements.get(elements.size() - 1)) { + sb.append(", "); + } + } + int left = size - elements.size(); + for (int i = 0; i < left; i++) { + sb.append(", i32 0"); + } + sb.append("]"); + } + return sb.toString(); + } +} diff --git a/midend/llvm/constant/IrConstantInt.java b/midend/llvm/constant/IrConstantInt.java new file mode 100644 index 0000000..f7c1c1a --- /dev/null +++ b/midend/llvm/constant/IrConstantInt.java @@ -0,0 +1,20 @@ +package midend.llvm.constant; + +import midend.llvm.type.IrInterType; + +public class IrConstantInt extends IrConstant { + private int value; + + public IrConstantInt(int value) { + super(IrInterType.INT32, value + ""); + this.value = value; + } + + public int getValue() { + return value; + } + + public String toString() { + return "i32 " + value; + } +} diff --git a/midend/llvm/constant/IrConstantStr.java b/midend/llvm/constant/IrConstantStr.java new file mode 100644 index 0000000..1e6e4b6 --- /dev/null +++ b/midend/llvm/constant/IrConstantStr.java @@ -0,0 +1,53 @@ +package midend.llvm.constant; + +import midend.llvm.type.IrArrayType; +import midend.llvm.type.IrPointerType; +import midend.llvm.type.IrInterType; + +public class IrConstantStr extends IrConstant { + private String value; + + public IrConstantStr(String value, String name) { + super(new IrPointerType( + new IrArrayType(IrInterType.INT8, getLen(value) + 1)), name); + this.value = value; + } + + public String getValue() { + return value; + } + + public static int getLen(String value) { + int len = 0; + for (int i = 0; i < value.length(); i++) { + if (value.charAt(i) == '\\') { + i++; + } else if (value.charAt(i) == '"') { + continue; + } + len++; + } + return len; + } + + public static String getRealStr(String str) { + boolean start = str.charAt(0) == '"'; + boolean end = str.charAt(str.length() - 1) == '"'; + if (start && end) { + return str.substring(1, str.length() - 1); + } else if (start) { + return str.substring(1); + } else if (end) { + return str.substring(0, str.length() - 1); + } + return str; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getName() + " = constant " + ((IrPointerType) getType()).getPointeeType()); + sb.append(" c\"" + getRealStr(value).replace("\\n", "\\0A")); + sb.append("\\00\""); + return sb.toString(); + } +} diff --git a/midend/llvm/instr/AllocateInstr.java b/midend/llvm/instr/AllocateInstr.java new file mode 100644 index 0000000..a6e3d25 --- /dev/null +++ b/midend/llvm/instr/AllocateInstr.java @@ -0,0 +1,21 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrPointerType; +import midend.llvm.type.IrType; + +public class AllocateInstr extends IrInstr { + private IrType pointeeType; + + public AllocateInstr(IrType pointeeType, String name) { // name即为局部变量的name,因为要声明一个局部变量 + super(new IrPointerType(pointeeType), name, IrInstrType.ALLOCA); + this.pointeeType = pointeeType; + } + + public IrType getPointeeType() { + return pointeeType; + } + + public String toString() { + return getName() + " = alloca " + this.pointeeType; + } +} diff --git a/midend/llvm/instr/AluInstr.java b/midend/llvm/instr/AluInstr.java new file mode 100644 index 0000000..c214d66 --- /dev/null +++ b/midend/llvm/instr/AluInstr.java @@ -0,0 +1,24 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrInterType; +import midend.llvm.value.IrValue; + +public class AluInstr extends IrInstr { + private AluType alutype; + + public AluInstr(String name, String op, IrValue left, IrValue right) { + super(IrInterType.INT32, name, IrInstrType.ALU); + this.alutype = AluType.getAluType(op); + addUse(left); + addUse(right); + } + + public AluType getAluType() { + return alutype; + } + + public String toString() { + return getName() + " = " + alutype.toString() + " " + getType() + + " " + getUse(0).getName() + ", " + getUse(1).getName(); + } +} diff --git a/midend/llvm/instr/AluType.java b/midend/llvm/instr/AluType.java new file mode 100644 index 0000000..2138ab8 --- /dev/null +++ b/midend/llvm/instr/AluType.java @@ -0,0 +1,53 @@ +package midend.llvm.instr; + +public enum AluType { + ADD, + SUB, + MUL, + SDIV, + SREM, + AND, + OR; + + public static AluType getAluType(String op) { + switch (op) { + case "+": + return ADD; + case "-": + return SUB; + case "*": + return MUL; + case "/": + return SDIV; + case "%": + return SREM; + case "&": + return AND; + case "|": + return OR; + default: + return null; + } + } + + public String toString() { + switch (this) { + case ADD: + return "add"; + case SUB: + return "sub"; + case MUL: + return "mul"; + case SDIV: + return "sdiv"; + case SREM: + return "srem"; + case AND: + return "and"; + case OR: + return "or"; + default: + return null; + } + } +} \ No newline at end of file diff --git a/midend/llvm/instr/BranchInstr.java b/midend/llvm/instr/BranchInstr.java new file mode 100644 index 0000000..9fe2d68 --- /dev/null +++ b/midend/llvm/instr/BranchInstr.java @@ -0,0 +1,33 @@ +package midend.llvm.instr; + +import midend.llvm.value.IrBasicBlock; +import midend.llvm.value.IrValue; +import midend.llvm.type.IrInterType; + +public class BranchInstr extends IrInstr { + public BranchInstr(String name, IrValue cond, IrBasicBlock trueBB, IrBasicBlock falseBB) { + super(IrInterType.VOID, name, IrInstrType.BR); + addUse(cond); + addUse(trueBB); + addUse(falseBB); + } + + public IrValue getCond() { + return getUse(0); + } + + public IrBasicBlock getTrueBB() { + return (IrBasicBlock) getUse(1); + } + + public IrBasicBlock getFalseBB() { + return (IrBasicBlock) getUse(2); + } + + public String toString() { + return "br i1 " + getCond().getName() + + ", label %" + getTrueBB().getName() + + ", label %" + getFalseBB().getName(); + } + +} diff --git a/midend/llvm/instr/CallInstr.java b/midend/llvm/instr/CallInstr.java new file mode 100644 index 0000000..29c1fae --- /dev/null +++ b/midend/llvm/instr/CallInstr.java @@ -0,0 +1,48 @@ +package midend.llvm.instr; + +import java.util.ArrayList; + +import midend.llvm.value.IrFuncValue; +import midend.llvm.value.IrValue; + +public class CallInstr extends IrInstr { + public CallInstr(String name, IrFuncValue func, ArrayList args) { + super(func.getRetType(), name, IrInstrType.CALL); + addUse(func); + for (IrValue arg : args) { + addUse(arg); + } + } + + public boolean callVoid() { + return getType().isVoid(); + } + + public IrFuncValue getCalledFunc() { + return (IrFuncValue) getUse(0); + } + + public ArrayList getArgs() { + ArrayList args = new ArrayList<>(); + for (int i = 1; i < getNumUses(); i++) { + args.add(getUse(i)); + } + return args; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + if (!callVoid()) { + sb.append(getName() + " = "); + } + sb.append("call " + getType() + " " + getCalledFunc().getName() + "("); + for (int i = 1; i < getNumUses(); i++) { + sb.append(getUse(i).getType() + " " + getUse(i).getName()); + if (i < getNumUses() - 1) { + sb.append(", "); + } + } + sb.append(")"); + return sb.toString(); + } +} diff --git a/midend/llvm/instr/CmpInstr.java b/midend/llvm/instr/CmpInstr.java new file mode 100644 index 0000000..99bdcef --- /dev/null +++ b/midend/llvm/instr/CmpInstr.java @@ -0,0 +1,32 @@ +package midend.llvm.instr; + +import midend.llvm.value.IrValue; +import midend.llvm.type.IrInterType; + +public class CmpInstr extends IrInstr { + private CmpType cmpType; + + public CmpInstr(String name, String op, IrValue lhs, IrValue rhs) { + super(IrInterType.BOOL, name, IrInstrType.CMP); + cmpType = CmpType.getCmpType(op); + addUse(lhs); + addUse(rhs); + } + + public CmpType getCmpType() { + return cmpType; + } + + public IrValue getLhs() { + return getUse(0); + } + + public IrValue getRhs() { + return getUse(1); + } + + public String toString() { + return getName() + " = " + "icmp " + cmpType.toString() + + " i32 " + getLhs().getName() + ", " + getRhs().getName(); + } +} diff --git a/midend/llvm/instr/CmpType.java b/midend/llvm/instr/CmpType.java new file mode 100644 index 0000000..921a5ec --- /dev/null +++ b/midend/llvm/instr/CmpType.java @@ -0,0 +1,48 @@ +package midend.llvm.instr; + +public enum CmpType { + EQ, + NE, + SGT, + SGE, + SLT, + SLE; + + public static CmpType getCmpType(String op) { + switch (op) { + case "==": + return EQ; + case "!=": + return NE; + case ">": + return SGT; + case ">=": + return SGE; + case "<": + return SLT; + case "<=": + return SLE; + default: + return null; + } + } + + public String toString() { + switch (this) { + case EQ: + return "eq"; + case NE: + return "ne"; + case SGT: + return "sgt"; + case SGE: + return "sge"; + case SLT: + return "slt"; + case SLE: + return "sle"; + default: + return null; + } + } +} diff --git a/midend/llvm/instr/ExtendInstr.java b/midend/llvm/instr/ExtendInstr.java new file mode 100644 index 0000000..4ce886d --- /dev/null +++ b/midend/llvm/instr/ExtendInstr.java @@ -0,0 +1,31 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrType; +import midend.llvm.value.IrValue; + +public class ExtendInstr extends IrInstr { + private IrType targetType; + + public ExtendInstr(String name, IrType targetType, IrValue src) { + super(targetType, name, IrInstrType.EXTEND); + this.targetType = targetType; + addUse(src); + } + + public IrValue getSrc() { + return getUse(0); + } + + public IrType getTargetType() { + return this.targetType; + } + + public IrType getSrcType() { + return getSrc().getType(); + } + + public String toString() { + return getName() + " = zext " + getSrc().getType() + + " " + getSrc().getName() + " to " + getTargetType(); + } +} diff --git a/midend/llvm/instr/GepInstr.java b/midend/llvm/instr/GepInstr.java new file mode 100644 index 0000000..825463c --- /dev/null +++ b/midend/llvm/instr/GepInstr.java @@ -0,0 +1,57 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrArrayType; +import midend.llvm.type.IrPointerType; +import midend.llvm.type.IrType; +import midend.llvm.value.IrValue; + +public class GepInstr extends IrInstr { + public GepInstr(IrValue pointer, IrValue offset, String name) { + super(new IrPointerType(getTargetType(pointer)), name, IrInstrType.GEP); + addUse(pointer); + addUse(offset); + } + + public IrValue getPointer() { + return getUse(0); + } + + public IrValue getOffset() { + return getUse(1); + } + + public String toString() { + IrValue pointer = this.getPointer(); + IrValue offset = this.getOffset(); + + IrPointerType pointerType = (IrPointerType) pointer.getType(); + IrType targetType = pointerType.getPointeeType(); + + if (targetType instanceof IrArrayType arrayType) { + return getName() + " = getelementptr inbounds " + + arrayType + ", " + + pointerType + " " + + pointer.getName() + ", i32 0, " + + offset.getType() + " " + + offset.getName(); + } else { + return getName() + " = getelementptr inbounds " + + targetType + ", " + + pointerType + " " + + pointer.getName() + ", " + + offset.getType() + " " + + offset.getName(); + } + } + + public static IrType getTargetType(IrValue pointer) { + IrType targetType = ((IrPointerType) pointer.getType()).getPointeeType(); + if (targetType instanceof IrArrayType arrayType) { + return arrayType.getElementType(); + } else if (targetType instanceof IrPointerType pointerType) { + return pointerType.getPointeeType(); + } else { + return targetType; + } + } +} diff --git a/midend/llvm/instr/GetIntInstr.java b/midend/llvm/instr/GetIntInstr.java new file mode 100644 index 0000000..7b860f1 --- /dev/null +++ b/midend/llvm/instr/GetIntInstr.java @@ -0,0 +1,17 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrInterType; + +public class GetIntInstr extends IrInstr { + public GetIntInstr(String name) { + super(IrInterType.INT32, name, IrInstrType.IO); + } + + public String toString() { + return getName() + " = call i32 @getint()"; + } + + public static String getIntDecl() { + return "declare i32 @getint()"; + } +} diff --git a/midend/llvm/instr/IrInstr.java b/midend/llvm/instr/IrInstr.java new file mode 100644 index 0000000..1a701e9 --- /dev/null +++ b/midend/llvm/instr/IrInstr.java @@ -0,0 +1,28 @@ +package midend.llvm.instr; + +import midend.llvm.use.IrUser; +import midend.llvm.value.IrBasicBlock; +import midend.llvm.type.IrType; + +public class IrInstr extends IrUser { + private IrInstrType type; + private IrBasicBlock block; + + public IrInstr(IrType type, String name, IrInstrType instrType) { + super(type, name); + this.type = instrType; + this.block = null; + } + + public IrInstrType getInstrType() { + return type; + } + + public IrBasicBlock getBBlock() { + return block; + } + + public void setBBlock(IrBasicBlock block) { + this.block = block; + } +} diff --git a/midend/llvm/instr/IrInstrType.java b/midend/llvm/instr/IrInstrType.java new file mode 100644 index 0000000..cfcce36 --- /dev/null +++ b/midend/llvm/instr/IrInstrType.java @@ -0,0 +1,18 @@ +package midend.llvm.instr; + +public enum IrInstrType { + ALU, + CMP, + CALL, + ALLOCA, + LOAD, + STORE, + GEP, + PHI, + EXTEND, + TRUNC, + BR, + RET, + JUMP, + IO +} diff --git a/midend/llvm/instr/JumpInstr.java b/midend/llvm/instr/JumpInstr.java new file mode 100644 index 0000000..9c00ea7 --- /dev/null +++ b/midend/llvm/instr/JumpInstr.java @@ -0,0 +1,20 @@ +package midend.llvm.instr; + +import midend.llvm.value.IrBasicBlock; +import midend.llvm.type.IrInterType; + +public class JumpInstr extends IrInstr { + public JumpInstr(IrBasicBlock targetBlock) { + super(IrInterType.VOID, "jump", IrInstrType.JUMP); + addUse(targetBlock); + } + + public IrBasicBlock getTargetBlock() { + return (IrBasicBlock) getUse(0); + } + + public String toString() { + return "br label " + "%" + getTargetBlock().getName(); + } +} +// TODO:所有的指令的基本块设置还需完善 \ No newline at end of file diff --git a/midend/llvm/instr/LoadInstr.java b/midend/llvm/instr/LoadInstr.java new file mode 100644 index 0000000..f9c4c23 --- /dev/null +++ b/midend/llvm/instr/LoadInstr.java @@ -0,0 +1,20 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrPointerType; +import midend.llvm.value.IrValue; + +public class LoadInstr extends IrInstr { + public LoadInstr(IrValue pointer, String name) { + super(((IrPointerType) pointer.getType()).getPointeeType(), name, IrInstrType.LOAD); + addUse(pointer); + } + + public IrValue getPointer() { + return getUse(0); + } + + public String toString() { + return getName() + " = load " + getType() + ", " + + getPointer().getType() + " " + getPointer().getName(); + } +} diff --git a/midend/llvm/instr/PutChInstr.java b/midend/llvm/instr/PutChInstr.java new file mode 100644 index 0000000..db9fff5 --- /dev/null +++ b/midend/llvm/instr/PutChInstr.java @@ -0,0 +1,19 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrInterType; +import midend.llvm.value.IrValue; + +public class PutChInstr extends IrInstr { + public PutChInstr(String name, IrValue putValue) { + super(IrInterType.VOID, name, IrInstrType.IO); + addUse(putValue); + } + + public String toString() { + return "call void @putch(i32 " + getUses().get(0).getName() + ")"; + } + + public static String putChDecl() { + return "declare void @putch(i32)"; + } +} diff --git a/midend/llvm/instr/PutIntInstr.java b/midend/llvm/instr/PutIntInstr.java new file mode 100644 index 0000000..f24d12d --- /dev/null +++ b/midend/llvm/instr/PutIntInstr.java @@ -0,0 +1,19 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrInterType; +import midend.llvm.value.IrValue; + +public class PutIntInstr extends IrInstr { + public PutIntInstr(String name, IrValue putValue) { + super(IrInterType.VOID, name, IrInstrType.IO); + addUse(putValue); + } + + public String toString() { + return "call void @putint(i32 " + getUses().get(0).getName() + ")"; + } + + public static String putIntDecl() { + return "declare void @putint(i32)"; + } +} diff --git a/midend/llvm/instr/PutStrInstr.java b/midend/llvm/instr/PutStrInstr.java new file mode 100644 index 0000000..a913114 --- /dev/null +++ b/midend/llvm/instr/PutStrInstr.java @@ -0,0 +1,26 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrInterType; +import midend.llvm.type.IrPointerType; +import midend.llvm.constant.IrConstantStr; + +public class PutStrInstr extends IrInstr { + private IrConstantStr strVal; + + public PutStrInstr(String name, IrConstantStr putValue) { + super(IrInterType.VOID, name, IrInstrType.IO); + addUse(putValue); + strVal = putValue; + } + + public static String putStrDecl() { + return "declare void @putstr(i8*)"; + } + + public String toString() { + IrPointerType ptrType = (IrPointerType) strVal.getType(); + return "call void @putstr(i8* getelementptr inbounds (" + + ptrType.getPointeeType() + ", " + ptrType + + " " + strVal.getName() + ", i32 0, i32 0))"; + } +} diff --git a/midend/llvm/instr/ReturnInstr.java b/midend/llvm/instr/ReturnInstr.java new file mode 100644 index 0000000..e4b80f5 --- /dev/null +++ b/midend/llvm/instr/ReturnInstr.java @@ -0,0 +1,20 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrInterType; +import midend.llvm.value.IrValue; + +public class ReturnInstr extends IrInstr { + public ReturnInstr(IrValue retValue) { + super(IrInterType.VOID, "ret", IrInstrType.RET); + addUse(retValue); + } + + public IrValue getRetValue() { + return getUse(0); + } + + public String toString() { + return getName() + (getRetValue() == null ? " void" : + " " + getRetValue().getType() + " " + getRetValue().getName()); + } +} diff --git a/midend/llvm/instr/StoreInstr.java b/midend/llvm/instr/StoreInstr.java new file mode 100644 index 0000000..cd8b229 --- /dev/null +++ b/midend/llvm/instr/StoreInstr.java @@ -0,0 +1,25 @@ +package midend.llvm.instr; + +import midend.llvm.value.IrValue; +import midend.llvm.type.IrInterType; + +public class StoreInstr extends IrInstr { + public StoreInstr(IrValue value, IrValue pointer) { + super(IrInterType.VOID, "store", IrInstrType.STORE); + addUse(value); + addUse(pointer); + } + + public IrValue getValue() { + return getUse(0); + } + + public IrValue getPointer() { + return getUse(1); + } + + public String toString() { + return getName() + " " + getValue().getType() + " " + getValue().getName() + + ", " + getPointer().getType() + " " + getPointer().getName(); + } +} diff --git a/midend/llvm/instr/TruncInstr.java b/midend/llvm/instr/TruncInstr.java new file mode 100644 index 0000000..c359a6e --- /dev/null +++ b/midend/llvm/instr/TruncInstr.java @@ -0,0 +1,31 @@ +package midend.llvm.instr; + +import midend.llvm.type.IrType; +import midend.llvm.value.IrValue; + +public class TruncInstr extends IrInstr { + private IrType targetType; + + public TruncInstr(IrType targetType, IrValue value, String name) { + super(targetType, name, IrInstrType.TRUNC); + addUse(value); + this.targetType = targetType; + } + + public IrValue getSrc() { + return getUse(0); + } + + public IrType getTargetType() { + return targetType; + } + + public IrType getSrcType() { + return getSrc().getType(); + } + + public String toString() { + return getName() + " = trunc " + getSrcType() + + " " + getSrc().getName() + " to " + getTargetType(); + } +} diff --git a/midend/llvm/type/IrArrayType.java b/midend/llvm/type/IrArrayType.java new file mode 100644 index 0000000..23f56e0 --- /dev/null +++ b/midend/llvm/type/IrArrayType.java @@ -0,0 +1,23 @@ +package midend.llvm.type; + +public class IrArrayType extends IrType { + private IrType elementType; + private int size; + + public IrArrayType(IrType elementType, int size) { + this.elementType = elementType; + this.size = size; + } + + public IrType getElementType() { + return elementType; + } + + public int getSize() { + return size; + } + + public String toString() { + return "[" + size + " x " + elementType.toString() + "]"; + } +} diff --git a/midend/llvm/type/IrBasicBlockType.java b/midend/llvm/type/IrBasicBlockType.java new file mode 100644 index 0000000..2ec12bb --- /dev/null +++ b/midend/llvm/type/IrBasicBlockType.java @@ -0,0 +1,10 @@ +package midend.llvm.type; + +public class IrBasicBlockType extends IrType { + public IrBasicBlockType() { + } + + public String toString() { + return ""; + } +} \ No newline at end of file diff --git a/midend/llvm/type/IrFuncType.java b/midend/llvm/type/IrFuncType.java new file mode 100644 index 0000000..5d4daf7 --- /dev/null +++ b/midend/llvm/type/IrFuncType.java @@ -0,0 +1,17 @@ +package midend.llvm.type; + +public class IrFuncType extends IrType { + private IrType returnType; + + public IrFuncType(IrType returnType) { + this.returnType = returnType; + } + + public IrType getReturnType() { + return returnType; + } + + public String toString() { + return returnType.toString(); + } +} diff --git a/midend/llvm/type/IrInterType.java b/midend/llvm/type/IrInterType.java new file mode 100644 index 0000000..13a711c --- /dev/null +++ b/midend/llvm/type/IrInterType.java @@ -0,0 +1,18 @@ +package midend.llvm.type; + +public class IrInterType extends IrType { + private int size; + + public IrInterType(int size) { + this.size = size; + } + + public static final IrInterType INT32 = new IrInterType(32); + public static final IrInterType INT8 = new IrInterType(8); + public static final IrInterType BOOL = new IrInterType(1); + public static final IrInterType VOID = new IrInterType(0); + + public String toString() { + return size != 0 ? "i" + size : "void"; + } +} diff --git a/midend/llvm/type/IrPointerType.java b/midend/llvm/type/IrPointerType.java new file mode 100644 index 0000000..052751b --- /dev/null +++ b/midend/llvm/type/IrPointerType.java @@ -0,0 +1,17 @@ +package midend.llvm.type; + +public class IrPointerType extends IrType { + private IrType pointeeType; + + public IrPointerType(IrType pointeeType) { + this.pointeeType = pointeeType; + } + + public IrType getPointeeType() { + return pointeeType; + } + + public String toString() { + return pointeeType.toString() + "*"; + } +} diff --git a/midend/llvm/type/IrType.java b/midend/llvm/type/IrType.java new file mode 100644 index 0000000..037a9e4 --- /dev/null +++ b/midend/llvm/type/IrType.java @@ -0,0 +1,74 @@ +package midend.llvm.type; + +import midend.llvm.IrBuilder; +import midend.llvm.constant.IrConstantInt; +import midend.llvm.instr.CmpInstr; +import midend.llvm.instr.ExtendInstr; +import midend.llvm.instr.TruncInstr; +import midend.llvm.value.IrValue; +import midend.llvm.instr.ExtendInstr; + +public class IrType { + public boolean isInt32() { + return this == IrInterType.INT32; + } + + public boolean isInt8() { + return this == IrInterType.INT8; + } + + public boolean isBool() { + return this == IrInterType.BOOL; + } + + public boolean isVoid() { + return this == IrInterType.VOID; + } + + public boolean isPointer() { + return this instanceof IrPointerType; + } + + public boolean isArray() { + return this instanceof IrArrayType; + } + + public boolean isFunc() { + return this instanceof IrFuncType; + } + + public boolean isBasicBlock() { + return this instanceof IrBasicBlockType; + } + + public String toString() { + return ""; + } + + public static IrValue convertType(IrValue originValue, IrType targetType) { + IrType originType = originValue.getType(); + if (targetType.isInt32()) { + if (originType.isInt32()) { + return originValue; + } else { + ExtendInstr ei = new ExtendInstr( + IrBuilder.getLocalName(), targetType, originValue); + IrBuilder.addInstr(ei); + return ei; + } + } else if (targetType.isBool()) { + if (originType.isBool()) { + return originValue; + } else { + CmpInstr nezero = new CmpInstr(IrBuilder.getLocalName(), "!=", + originValue, new IrConstantInt(0)); + IrBuilder.addInstr(nezero); + return nezero; + } + } else if (targetType.isArray()) { + IrArrayType arrayType = (IrArrayType) targetType; + return convertType(originValue, arrayType.getElementType()); + } + return originValue; + } +} diff --git a/midend/llvm/use/IrUse.java b/midend/llvm/use/IrUse.java new file mode 100644 index 0000000..038fa3f --- /dev/null +++ b/midend/llvm/use/IrUse.java @@ -0,0 +1,21 @@ +package midend.llvm.use; + +import midend.llvm.value.IrValue; + +public class IrUse { + private IrValue value; + private IrUser user; + + public IrUse(IrValue value, IrUser user) { + this.value = value; + this.user = user; + } + + public IrValue getValue() { + return value; + } + + public IrUser getUser() { + return user; + } +} diff --git a/midend/llvm/use/IrUser.java b/midend/llvm/use/IrUser.java new file mode 100644 index 0000000..c699e5b --- /dev/null +++ b/midend/llvm/use/IrUser.java @@ -0,0 +1,38 @@ +package midend.llvm.use; + +import java.util.ArrayList; + +import midend.llvm.value.IrValue; +import midend.llvm.type.IrType; + +public class IrUser extends IrValue { + private ArrayList uses; + + public IrUser(IrType type, String name) { + super(type, name); + this.uses = new ArrayList<>(); + } + + public ArrayList getUses() { + return uses; + } + + public void addUse(IrValue value) { + if (value == null) { + return; + } + uses.add(value); + value.addUser(this); + } + + public IrValue getUse(int index) { + if (index >= uses.size()) { + return null; + } + return uses.get(index); + } + + public int getNumUses() { + return uses.size(); + } +} diff --git a/midend/llvm/value/IrBasicBlock.java b/midend/llvm/value/IrBasicBlock.java new file mode 100644 index 0000000..2bf2100 --- /dev/null +++ b/midend/llvm/value/IrBasicBlock.java @@ -0,0 +1,120 @@ +package midend.llvm.value; + +import java.util.ArrayList; +import java.util.HashSet; + +import midend.llvm.instr.IrInstr; +import midend.llvm.instr.ReturnInstr; +import midend.llvm.type.IrBasicBlockType; + +public class IrBasicBlock extends IrValue { + private ArrayList instrs; + private IrFuncValue func; + private ArrayList preds; //前驱 + private ArrayList succs; //后继 + private HashSet domied; //支配该节点 + private IrBasicBlock directDomi; + private HashSet directDomies; //该节点直接支配 + private HashSet domiFrontier; + + public IrBasicBlock(String name, IrFuncValue func) { + super(new IrBasicBlockType(), name); + this.func = func; + instrs = new ArrayList<>(); + preds = new ArrayList<>(); + succs = new ArrayList<>(); + domied = new HashSet<>(); + directDomi = null; + directDomies = new HashSet<>(); + domiFrontier = new HashSet<>(); + } + + public void addInstr(IrInstr instr) { + instrs.add(instr); + instr.setBBlock(this); + } + + public IrFuncValue getFunc() { + return func; + } + + public boolean isEmpty() { + return instrs.isEmpty(); + } + + public boolean isEntry() { + return this.func.getBBlock(0) == this; + } + + public ArrayList getPreds() { + return preds; + } + + public ArrayList getSuccs() { + return succs; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getName() + ":\n\t"); + for (IrInstr instr : instrs) { + sb.append(instr.toString()); + if (instr != instrs.get(instrs.size() - 1)) { + sb.append("\n\t"); + } + } + return sb.toString(); + } + + public boolean lastIsReturn() { + if (instrs.isEmpty()) { + return false; + } + return instrs.get(instrs.size() - 1) instanceof ReturnInstr; + } + + public void clearCfg() { + this.preds.clear(); + this.succs.clear(); + domied.clear(); + directDomi = null; + directDomies.clear(); + domiFrontier.clear(); + } + + public ArrayList getInstrs() { + return instrs; + } + + public void addPred(IrBasicBlock bb) { + this.preds.add(bb); + } + + public void addSucc(IrBasicBlock bb) { + this.succs.add(bb); + } + + public void addDomied(IrBasicBlock bb) { + this.domied.add(bb); + } + + public void addDirectDomies(IrBasicBlock bb) { + this.directDomies.add(bb); + } + + public void addDomiFrontier(IrBasicBlock bb) { + this.domiFrontier.add(bb); + } + + public void setDirectDomi(IrBasicBlock bb) { + this.directDomi = bb; + } + + public HashSet getDomied() { + return domied; + } + + public IrBasicBlock getDirectDomi() { + return this.directDomi; + } +} diff --git a/midend/llvm/value/IrFuncValue.java b/midend/llvm/value/IrFuncValue.java new file mode 100644 index 0000000..bb570c3 --- /dev/null +++ b/midend/llvm/value/IrFuncValue.java @@ -0,0 +1,71 @@ +package midend.llvm.value; + +import java.util.ArrayList; +import midend.llvm.type.IrType; +import midend.llvm.IrBuilder; +import midend.llvm.instr.ReturnInstr; +import midend.llvm.type.IrFuncType; + +public class IrFuncValue extends IrValue { + private ArrayList params; + private ArrayList bblocks; + + public IrFuncValue(String name, IrType retType) { + super(new IrFuncType(retType), name); + params = new ArrayList<>(); + bblocks = new ArrayList<>(); + } + + public ArrayList getParams() { + return params; + } + + public ArrayList getBBlocks() { + return bblocks; + } + + public IrBasicBlock getBBlock(int index) { + return bblocks.get(index); + } + + public void addParam(IrValue param) { + params.add(param); + } + + public void addBBlock(IrBasicBlock bblock) { + bblocks.add(bblock); + } + + public boolean isMain() { + return getName().equals("@main"); + } + + public IrType getRetType() { + return ((IrFuncType) getType()).getReturnType(); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("define dso_local " + this.getRetType() + " " + this.getName() + "("); + for (int i = 0; i < params.size(); i++) { + sb.append(params.get(i).getType() + " " + params.get(i).getName()); + if (i < params.size() - 1) { + sb.append(", "); + } + } + sb.append(") {\n"); + for (IrBasicBlock bblock : bblocks) { + sb.append(bblock.toString() + "\n"); + } + sb.append("}\n"); + return sb.toString(); + } + + public void checkReturn() { + IrBasicBlock currentBB = IrBuilder.getCurrentBB(); + if (!currentBB.lastIsReturn()) { + ReturnInstr returnInstr = new ReturnInstr(null); // 确保没有return的情况只有void + IrBuilder.addInstr(returnInstr); + } + } +} diff --git a/midend/llvm/value/IrGlobalValue.java b/midend/llvm/value/IrGlobalValue.java new file mode 100644 index 0000000..60fa33c --- /dev/null +++ b/midend/llvm/value/IrGlobalValue.java @@ -0,0 +1,28 @@ +package midend.llvm.value; + +import midend.llvm.type.IrType; +import midend.llvm.constant.IrConstant; + +public class IrGlobalValue extends IrValue { + private boolean isConstant; + private IrConstant initVal; + + public IrGlobalValue(IrType type, String name, boolean isConstant, IrConstant initVal) { + super(type, name); + this.isConstant = isConstant; + this.initVal = initVal; + } + + public boolean isConstant() { + return isConstant; + } + + public IrConstant getInitVal() { + return initVal; + } + + public String toString() { + return isConstant ? getName() + " = dso_local constant " + initVal.toString() : + getName() + " = dso_local global " + initVal.toString(); + } +} diff --git a/midend/llvm/value/IrLoop.java b/midend/llvm/value/IrLoop.java new file mode 100644 index 0000000..9101af4 --- /dev/null +++ b/midend/llvm/value/IrLoop.java @@ -0,0 +1,32 @@ +package midend.llvm.value; + +public class IrLoop { + private IrBasicBlock condBB; + private IrBasicBlock bodyBB; + private IrBasicBlock stepBB; + private IrBasicBlock followBB; + + public IrLoop(IrBasicBlock condBB, IrBasicBlock bodyBB, + IrBasicBlock stepBB, IrBasicBlock followBB) { + this.condBB = condBB; + this.bodyBB = bodyBB; + this.stepBB = stepBB; + this.followBB = followBB; + } + + public IrBasicBlock getCondBB() { + return condBB; + } + + public IrBasicBlock getBodyBB() { + return bodyBB; + } + + public IrBasicBlock getStepBB() { + return stepBB; + } + + public IrBasicBlock getFollowBB() { + return followBB; + } +} diff --git a/midend/llvm/value/IrValue.java b/midend/llvm/value/IrValue.java new file mode 100644 index 0000000..8bb31c4 --- /dev/null +++ b/midend/llvm/value/IrValue.java @@ -0,0 +1,38 @@ +package midend.llvm.value; + +import java.util.ArrayList; + +import midend.llvm.type.IrType; +import midend.llvm.use.IrUser; + +public class IrValue { + private IrType type; + private String name; + private ArrayList users; + + public IrValue(IrType type, String name) { + this.type = type; + this.name = name; + this.users = new ArrayList<>(); + } + + public IrType getType() { + return type; + } + + public String getName() { + return name; + } + + public ArrayList getUsers() { + return users; + } + + public void addUser(IrUser user) { + users.add(user); + } + + public String toString() { + return type.toString() + " " + name; + } +} diff --git a/midend/optimize/CfgMake.java b/midend/optimize/CfgMake.java new file mode 100644 index 0000000..b8cd586 --- /dev/null +++ b/midend/optimize/CfgMake.java @@ -0,0 +1,112 @@ +package midend.optimize; + +import java.util.HashSet; + +import midend.llvm.instr.IrInstr; +import midend.llvm.instr.IrInstrType; +import midend.llvm.instr.JumpInstr; +import midend.llvm.value.IrBasicBlock; +import midend.llvm.value.IrFuncValue; +import midend.llvm.instr.BranchInstr; + +public class CfgMake extends Optimizer { + public void optimize() { + for (IrFuncValue func : getIrModule().getFuncs()) { + for (IrBasicBlock bb : func.getBBlocks()) { + bb.clearCfg(); + } + } + makeCfg(); + } + + public void makeCfg() { + for (IrFuncValue func : getIrModule().getFuncs()) { + for (IrBasicBlock bb : func.getBBlocks()) { + for (IrInstr instr : bb.getInstrs()) { + if (instr.getInstrType() == IrInstrType.BR) { + BranchInstr branchInstr = (BranchInstr) instr; + IrBasicBlock trueBlock = branchInstr.getTrueBB(); + IrBasicBlock falseBlock = branchInstr.getFalseBB(); + bb.addSucc(trueBlock); + bb.addSucc(falseBlock); + trueBlock.addPred(bb); + falseBlock.addPred(bb); + } else if (instr.getInstrType() == IrInstrType.JUMP) { + JumpInstr jumpInstr = (JumpInstr) instr; + IrBasicBlock jumpBlock = jumpInstr.getTargetBlock(); + bb.addSucc(jumpBlock); + jumpBlock.addPred(bb); + } + } + } + } + } + + public void makeDomination() { + for (IrFuncValue func : getIrModule().getFuncs()) { + for (IrBasicBlock bb : func.getBBlocks()) { + HashSet canArrive = new HashSet<>(); + handleArrive(func.getBBlock(0), bb, canArrive); + for (IrBasicBlock block : func.getBBlocks()) { + if (!canArrive.contains(block)) { + block.addDomied(bb); + } + } + } + } + } + + public void handleArrive(IrBasicBlock entryBlock, + IrBasicBlock deleteBlock, HashSet canArrive) { + if (entryBlock == deleteBlock) { + return; + } else { + if (!canArrive.contains(entryBlock)) { + canArrive.add(entryBlock); + } + for (IrBasicBlock succ : entryBlock.getSuccs()) { + if (succ != deleteBlock && !canArrive.contains(succ)) { + handleArrive(succ, deleteBlock, canArrive); + } + } + } + } + + public void makeDirectDomi() { + for (IrFuncValue func : getIrModule().getFuncs()) { + for (IrBasicBlock bb : func.getBBlocks()) { + for (IrBasicBlock domi : bb.getDomied()) { + HashSet bbDomi = bb.getDomied(); + HashSet domiDomi = domi.getDomied(); + for (IrBasicBlock domiDomiBB : domiDomi) { + if (bbDomi.contains(domiDomiBB)) { + bbDomi.remove(domiDomiBB); + } + } + if (bbDomi.size() == 1 && bbDomi.contains(bb)) { + bb.setDirectDomi(domi); + domi.addDirectDomies(bb); + break; + } + } + } + } + } + + public void makeDomiFrontier() { + for (IrFuncValue func : getIrModule().getFuncs()) { + for (IrBasicBlock bb : func.getBBlocks()) { + for (IrBasicBlock succ : bb.getSuccs()) { + IrBasicBlock currentBB = bb; + while (!succ.getDomied().contains(currentBB) || currentBB == succ) { + currentBB.addDomiFrontier(succ); + currentBB = currentBB.getDirectDomi(); + if (currentBB == null) { + break; + } + } + } + } + } + } +} diff --git a/midend/optimize/Optimizer.java b/midend/optimize/Optimizer.java new file mode 100644 index 0000000..8528aef --- /dev/null +++ b/midend/optimize/Optimizer.java @@ -0,0 +1,19 @@ +package midend.optimize; + +import midend.llvm.IrModule; + +public class Optimizer { + private static IrModule irModule; + + public void setIrModule(IrModule irModule) { + Optimizer.irModule = irModule; + } + + public static IrModule getIrModule() { + return irModule; + } + + public void optimize() { + + } +} diff --git a/midend/symbol/ArraySymbol.java b/midend/symbol/ArraySymbol.java new file mode 100644 index 0000000..6eb2a26 --- /dev/null +++ b/midend/symbol/ArraySymbol.java @@ -0,0 +1,20 @@ +package midend.symbol; + +public class ArraySymbol extends Symbol { + private int dim; // -1 means unknown + + public ArraySymbol(String name, SymbolType type, int line, int dim) { + super(name, type, line); + this.dim = dim; + } + + public int getDim() { + return dim; + } + + public void fullValue() { + for (int i = getValueList().size(); i < dim; i++) { + addValue(0); + } + } +} diff --git a/midend/symbol/FuncSymbol.java b/midend/symbol/FuncSymbol.java new file mode 100644 index 0000000..5a80b36 --- /dev/null +++ b/midend/symbol/FuncSymbol.java @@ -0,0 +1,50 @@ +package midend.symbol; + +import java.util.ArrayList; + +public class FuncSymbol extends Symbol { + private int returnType; // 0 for void, 1 for int + private ArrayList paramList; // 0 for var, 1 for array + private ArrayList paramSymbolList; + + public FuncSymbol(String name, SymbolType type, int line, int returnType) { + super(name, type, line); + paramList = new ArrayList<>(); + paramSymbolList = new ArrayList<>(); + this.returnType = returnType; + } + + public void addParam(int param) { + paramList.add(param); + } + + public void addParamSymbol(Symbol paramSymbol) { + paramSymbolList.add(paramSymbol); + } + + public int getParamNum() { + return paramList.size(); + } + + public int getReturnType() { + return returnType; + } + + public int getParamType(int index) { + return paramList.get(index); + } + + public void printParams() { + for (int i = 0; i < paramList.size(); i++) { + System.out.print(paramList.get(i) + " "); + } + } + + public ArrayList getParamList() { + return paramList; + } + + public ArrayList getParamSymbolList() { + return paramSymbolList; + } +} diff --git a/midend/symbol/Symbol.java b/midend/symbol/Symbol.java new file mode 100644 index 0000000..e9ceb3d --- /dev/null +++ b/midend/symbol/Symbol.java @@ -0,0 +1,77 @@ +package midend.symbol; + +import java.util.ArrayList; + +import midend.llvm.value.IrValue; + +public class Symbol { + private String name; + private SymbolType type; + private int line; + private ArrayList valueList; + private IrValue irValue; + + public Symbol(String name, SymbolType type, int line) { + this.name = name; + this.type = type; + this.line = line; + valueList = new ArrayList<>(); + irValue = null; + } + + public void setIrValue(IrValue irValue) { + this.irValue = irValue; + } + + public IrValue getIrValue() { + return irValue; + } + + public void addValue(int value) { + valueList.add(value); + } + + public void addValue(ArrayList valueList) { + this.valueList.addAll(valueList); + } + + public ArrayList getValueList() { + return valueList; + } + + public int getValue(int index) { + return valueList.get(index); + } + + public String getName() { + return name; + } + + public String getTypeStr() { + return type.toString(); + } + + public SymbolType getType() { + return type; + } + + public int getLine() { + return line; + } + + public String toString() { + return name + " " + type.toString() + "\n"; + } + + public boolean isThatType(int type) { // 0 for normal var, 1 for array, 2 for func + if (type == 1) { + return this.type == SymbolType.INT_ARRAY || this.type == SymbolType.CONST_INT_ARRAY + || this.type == SymbolType.STATIC_INT_ARRAY; + } else if (type == 2) { + return this.type == SymbolType.INT_FUNC || this.type == SymbolType.VOID_FUNC; + } else { + return this.type == SymbolType.INT || this.type == SymbolType.CONST_INT + || this.type == SymbolType.STATIC_INT; + } + } +} diff --git a/midend/symbol/SymbolManager.java b/midend/symbol/SymbolManager.java new file mode 100644 index 0000000..f5db4a0 --- /dev/null +++ b/midend/symbol/SymbolManager.java @@ -0,0 +1,136 @@ +package midend.symbol; + +import java.util.ArrayList; + +import error.Errors; + +public class SymbolManager { + public static ArrayList symbolTableList; + public static ArrayList sequence; + public static SymbolTable currentTable; + public static int currentSequence; + + public static void init() { + symbolTableList = new ArrayList<>(); + sequence = new ArrayList<>(); + currentTable = null; + currentSequence = -1; + } + + public static void addSymbolTable() { + SymbolTable symbolTable = new SymbolTable(symbolTableList.size() + 1); + symbolTableList.add(symbolTable); + sequence.add(symbolTable.getTableId()); + currentSequence++; + if (currentTable != null) { + symbolTable.setParentTable(currentTable); + } + currentTable = symbolTable; + } + + public static ArrayList getSymbolTableList() { + return symbolTableList; + } + + public static void releaseSymbolTable(int tableId) { + symbolTableList.get(tableId - 1).release(); + currentTable = null; + for (int i = symbolTableList.size() - 1; i >= 0; i--) { + if (!symbolTableList.get(i).isReleased()) { + currentTable = symbolTableList.get(i); + currentSequence++; + sequence.add(currentTable.getTableId()); + break; + } + } + } + + public static void releaseSymbolTable() { + releaseSymbolTable(currentTable.getTableId()); + } + + public static int getSymbolTableSize() { + return symbolTableList.size(); + } + + public static void addSymbol(Symbol symbol, Errors errors) { + currentTable.addSymbol(symbol, errors); + } + + public static String getSymbolTableInfo() { + String info = ""; + for (SymbolTable symbolTable : symbolTableList) { + info += symbolTable.toString(); + } + return info; + } + + public static Symbol getSymbol(String name) { + SymbolTable stable = currentTable; + Symbol symbol = null; + while (stable != null) { + symbol = stable.getSymbol(name); + if (symbol != null) { + break; + } + stable = stable.getParentTable(); + } + return symbol; + } + + public static Symbol getSymbol(String name, boolean defined) { + SymbolTable stable = currentTable; + Symbol symbol = null; + while (stable != null) { + symbol = stable.getSymbol(name); + if (symbol != null && symbol.getIrValue() != null) { + break; + } + stable = stable.getParentTable(); + } + return symbol; + } + + public static void nextTable() { + currentSequence++; + if (currentSequence >= sequence.size()) { + return; + } + currentTable = symbolTableList.get(sequence.get(currentSequence) - 1); + } + + public static void lastTable() { + currentSequence--; + if (currentSequence < 0) { + currentSequence = 0; + currentTable = symbolTableList.get(0); + return; + } + currentTable = symbolTableList.get(sequence.get(currentSequence) - 1); + } + + public static void reset() { + currentSequence = -1; + currentTable = null; + } + + public static boolean IsGlobal() { + return currentTable.getTableId() == 1; + } + + public static ArrayList getSequence() { + return sequence; + } + + public static int getCurrentSequence() { + return currentSequence; + } + + public static int getCurrentTableId() { + return sequence.get(currentSequence); + } + + public static SymbolTable getCurrentTable() { + return currentTable; + } +} diff --git a/midend/symbol/SymbolTable.java b/midend/symbol/SymbolTable.java new file mode 100644 index 0000000..1b01a61 --- /dev/null +++ b/midend/symbol/SymbolTable.java @@ -0,0 +1,68 @@ +package midend.symbol; + +import java.util.ArrayList; +import java.util.HashMap; + +import error.Error; +import error.ErrorType; +import error.Errors; + +public class SymbolTable { + private ArrayList symbolList; + private HashMap symbolMap; + private int tableId; + private boolean isReleased; + private SymbolTable parentTable; + + public SymbolTable(int tableId) { + this.tableId = tableId; + isReleased = false; + symbolList = new ArrayList<>(); + symbolMap = new HashMap<>(); + parentTable = null; + } + + public int getTableId() { + return tableId; + } + + public boolean isReleased() { + return isReleased; + } + + public void release() { + isReleased = true; + } + + public void addSymbol(Symbol symbol, Errors errors) { + if (symbolMap.containsKey(symbol.getName())) { + errors.addError(new Error(symbol.getLine(), ErrorType.b)); + return; + } + symbolList.add(symbol); + symbolMap.put(symbol.getName(), symbol); + } + + public void setParentTable(SymbolTable parentTable) { + this.parentTable = parentTable; + } + + public SymbolTable getParentTable() { + return parentTable; + } + + public Symbol getSymbol(String name) { + if (symbolMap.containsKey(name)) { + return symbolMap.get(name); + } + return null; + } + + public String toString() { + String info = ""; + for (Symbol symbol : symbolList) { + info += tableId + " " + symbol.toString(); + } + return info; + } +} diff --git a/midend/symbol/SymbolType.java b/midend/symbol/SymbolType.java new file mode 100644 index 0000000..855c010 --- /dev/null +++ b/midend/symbol/SymbolType.java @@ -0,0 +1,22 @@ +package midend.symbol; + +public enum SymbolType { + CONST_INT("ConstInt"), + CONST_INT_ARRAY("ConstIntArray"), + STATIC_INT("StaticInt"), + INT("Int"), + INT_ARRAY("IntArray"), + STATIC_INT_ARRAY("StaticIntArray"), + VOID_FUNC("VoidFunc"), + INT_FUNC("IntFunc"); + + private final String type; + SymbolType(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } +} diff --git a/midend/visit/Visitor.java b/midend/visit/Visitor.java new file mode 100644 index 0000000..2b902d5 --- /dev/null +++ b/midend/visit/Visitor.java @@ -0,0 +1,36 @@ +package midend.visit; + +import java.util.ArrayList; + +import frontend.ast.CompUnit; +import frontend.ast.decl.Decl; +import frontend.ast.func.FuncDef; +import frontend.ast.func.MainFuncDef; +import midend.symbol.SymbolManager; + +public class Visitor { + private CompUnit compUnit; + + public Visitor(CompUnit compUnit) { + this.compUnit = compUnit; + SymbolManager.reset(); + SymbolManager.nextTable(); + } + + public void visit() { + ArrayList decls = this.compUnit.GetDecls(); + ArrayList funcDefs = this.compUnit.GetFuncDefs(); + MainFuncDef mainFuncDef = this.compUnit.GetMainFuncDef(); + + for (Decl decl : decls) { + VisitorDecl.visitDecl(decl); + } + + for (FuncDef funcDef : funcDefs) { + VisitorFuncDef.visitFuncDef(funcDef); + } + + VisitorFuncDef.visitMainFuncDef(mainFuncDef); + } + //:TODO:符号表的变换,什么时候往前进一个符号表,这需要人工手工来操作 +} diff --git a/midend/visit/VisitorBlock.java b/midend/visit/VisitorBlock.java new file mode 100644 index 0000000..05c2930 --- /dev/null +++ b/midend/visit/VisitorBlock.java @@ -0,0 +1,35 @@ +package midend.visit; + +import java.util.ArrayList; + +import frontend.ast.block.Block; +import frontend.ast.block.BlockItem; +import frontend.ast.block.Stmt; +import frontend.ast.decl.Decl; +import midend.symbol.SymbolManager; + +public class VisitorBlock { + public static void visitBlock(Block block) { + if (!block.isFuncBlock()) { + SymbolManager.nextTable(); + } + // System.out.println("(block)now table: " + SymbolManager.getCurrentTableId()); + // System.out.println("bsequence: " + SymbolManager.getCurrentSequence());//TODO:debug + ArrayList blockItems = block.getBlockItems(); + for (BlockItem blockItem : blockItems) { + visitBlockItem(blockItem); + } + if (!block.isFuncBlock()) { + SymbolManager.nextTable(); + } + // System.out.println("(block)now table: " + SymbolManager.getCurrentTableId());//TODO:debug + } + + public static void visitBlockItem(BlockItem blockItem) { + if (blockItem.getChild(0) instanceof Decl) { + VisitorDecl.visitDecl((Decl) blockItem.getChild(0)); + } else { + VisitorStmt.visitStmt((Stmt) blockItem.getChild(0)); + } + } +} diff --git a/midend/visit/VisitorDecl.java b/midend/visit/VisitorDecl.java new file mode 100644 index 0000000..601a771 --- /dev/null +++ b/midend/visit/VisitorDecl.java @@ -0,0 +1,167 @@ +package midend.visit; + +import java.util.ArrayList; + +import frontend.ast.decl.ConstDecl; +import frontend.ast.decl.ConstDef; +import frontend.ast.decl.Decl; +import frontend.ast.decl.VarDecl; +import frontend.ast.decl.VarDef; +import frontend.ast.exp.ConstExp; +import frontend.ast.exp.Exp; +import frontend.ast.token.TokenNode; +import frontend.lexer.Token; +import midend.llvm.IrBuilder; +import midend.llvm.constant.IrConstant; +import midend.llvm.constant.IrConstantArray; +import midend.llvm.constant.IrConstantInt; +import midend.llvm.instr.AllocateInstr; +import midend.llvm.instr.StoreInstr; +import midend.llvm.instr.GepInstr; +import midend.llvm.type.IrArrayType; +import midend.llvm.type.IrFuncType; +import midend.llvm.type.IrInterType; +import midend.llvm.type.IrPointerType; +import midend.llvm.type.IrType; +import midend.llvm.value.IrGlobalValue; +import midend.llvm.value.IrValue; +import midend.symbol.SymbolType; +import midend.symbol.ArraySymbol; +import midend.symbol.Symbol; +import midend.symbol.SymbolManager; + +public class VisitorDecl { + public static void visitDecl(Decl decl) { + if (decl.getChild(0) instanceof ConstDecl) { + visitConstDecl((ConstDecl) decl.getChild(0)); + } else { + visitVarDecl((VarDecl) decl.getChild(0)); + } + } + + public static void visitConstDecl(ConstDecl constDecl) { + ArrayList constDefs = constDecl.GetConstDefs(); + for (ConstDef constDef : constDefs) { + visitConstDef(constDef); + } + } + + public static void visitVarDecl(VarDecl varDecl) { + ArrayList varDefs = varDecl.GetVarDefs(); + for (VarDef varDef : varDefs) { + visitVarDef(varDef); + } + } + + public static void visitConstDef(ConstDef constDef) { + Symbol symbol = SymbolManager.getSymbol(((TokenNode) constDef.getChild(0)).getValue()); + if (SymbolManager.IsGlobal()) { // 全局变量下直接声明 + IrGlobalValue irGlobalValue = new IrGlobalValue( + new IrPointerType(getSymbolIrType(symbol)), + IrBuilder.getGlobalName(), true, getSymbolIrConst(symbol)); + IrBuilder.addNewGlobal(irGlobalValue); + symbol.setIrValue(irGlobalValue); + } else { // 局部变量需要分配地址再存值 + AllocateInstr allocateInstr = new AllocateInstr(getSymbolIrType(symbol), + IrBuilder.getLocalName()); + IrBuilder.addInstr(allocateInstr); + symbol.setIrValue(allocateInstr); + ArrayList valueList = symbol.getValueList(); + if (!(symbol instanceof ArraySymbol)) { + StoreInstr storeInstr = new StoreInstr(getSymbolIrConst(symbol), + allocateInstr); + IrBuilder.addInstr(storeInstr); + } else { + for (int i = 0; i < valueList.size(); i++) { + GepInstr gepInstr = new GepInstr(allocateInstr, + new IrConstantInt(i), IrBuilder.getLocalName()); + IrBuilder.addInstr(gepInstr); + IrValue initValue = new IrConstantInt(valueList.get(i)); + StoreInstr storeInstr = new StoreInstr(initValue, gepInstr); + IrBuilder.addInstr(storeInstr); + } + } + } + } + + private static void visitVarDef(VarDef varDef) { + Symbol symbol = SymbolManager.getSymbol(((TokenNode) varDef.getChild(0)).getValue()); + if (SymbolManager.IsGlobal()) { + IrGlobalValue irGlobalValue = new IrGlobalValue( + new IrPointerType(getSymbolIrType(symbol)), + IrBuilder.getGlobalName(), false, getSymbolIrConst(symbol)); + IrBuilder.addNewGlobal(irGlobalValue); + symbol.setIrValue(irGlobalValue); + } else { // Think:static修饰的变量该如何实现 + visitLocalVarDef(varDef, symbol); + } + } + + private static void visitLocalVarDef(VarDef varDef, Symbol symbol) { + if (symbol.getType().equals(SymbolType.STATIC_INT) || + symbol.getType().equals(SymbolType.STATIC_INT_ARRAY)) { + // 当为局部变量且为static修饰的变量的时候,将其作为全局变量处理 + IrGlobalValue irGlobalValue = new IrGlobalValue( + new IrPointerType(getSymbolIrType(symbol)), + IrBuilder.getGlobalName(), false, getSymbolIrConst(symbol)); + IrBuilder.addNewGlobal(irGlobalValue); + symbol.setIrValue(irGlobalValue); + return; + } + AllocateInstr allocateInstr = new AllocateInstr( + getSymbolIrType(symbol), IrBuilder.getLocalName()); + IrBuilder.addInstr(allocateInstr); + if (!(symbol instanceof ArraySymbol)) { // 非数组变量 + if (varDef.HaveInitVal()) { + Exp exp = varDef.getInitVal().getExpList().get(0); + IrValue irExp = VisitorExp.visitExp(exp); + StoreInstr storeInstr = new StoreInstr(irExp, allocateInstr); + IrBuilder.addInstr(storeInstr); + } + } else { // 数组变量 + if (varDef.HaveInitVal()) { + ArrayList expList = varDef.getInitVal().getExpList(); + for (int i = 0; i < expList.size(); i++) { + IrValue irExp = VisitorExp.visitExp(expList.get(i)); + irExp = IrType.convertType(irExp, IrInterType.INT32); + GepInstr gepInstr = new GepInstr(allocateInstr, + new IrConstantInt(i), IrBuilder.getLocalName()); + IrBuilder.addInstr(gepInstr); + StoreInstr storeInstr = new StoreInstr(irExp, gepInstr); + IrBuilder.addInstr(storeInstr); + } + } + } + symbol.setIrValue(allocateInstr); + } + + public static IrType getSymbolIrType(Symbol symbol) { + SymbolType st = symbol.getType(); + if (st.equals(SymbolType.INT) || st.equals(SymbolType.CONST_INT) + || st.equals(SymbolType.STATIC_INT)) { + return IrInterType.INT32; + } else if (st.equals(SymbolType.INT_ARRAY) || st.equals(SymbolType.CONST_INT_ARRAY) + || st.equals(SymbolType.STATIC_INT_ARRAY)) { + return new IrArrayType(IrInterType.INT32, ((ArraySymbol) symbol).getDim()); + } else { + if (st.equals(SymbolType.INT_FUNC)) { + return new IrFuncType(IrInterType.INT32); + } else { + return new IrFuncType(IrInterType.VOID); + } + } + } + + public static IrConstant getSymbolIrConst(Symbol symbol) { + ArrayList valueList = symbol.getValueList(); + if (symbol instanceof ArraySymbol) { + ArrayList elements = new ArrayList<>(); + for (int i = 0; i < valueList.size(); i++) { + elements.add(new IrConstantInt(valueList.get(i))); + } + return new IrConstantArray(symbol.getName(), elements, ((ArraySymbol) symbol).getDim()); + } else { + return valueList.isEmpty() ? new IrConstantInt(0) : new IrConstantInt(valueList.get(0)); + } + } +} diff --git a/midend/visit/VisitorExp.java b/midend/visit/VisitorExp.java new file mode 100644 index 0000000..e91c251 --- /dev/null +++ b/midend/visit/VisitorExp.java @@ -0,0 +1,264 @@ +package midend.visit; + +import frontend.ast.exp.Exp; +import frontend.ast.exp.LAndExp; +import frontend.ast.exp.LOrExp; +import frontend.ast.exp.LVal; + +import java.util.ArrayList; + +import frontend.ast.exp.AddExp; +import frontend.ast.exp.EqExp; +import frontend.ast.exp.MulExp; +import frontend.ast.exp.NumberExp; +import frontend.ast.exp.PrimaryExp; +import frontend.ast.exp.RelExp; +import frontend.ast.exp.UnaryExp; +import frontend.ast.exp.UnaryOp; +import frontend.ast.exp.Cond; +import frontend.ast.token.TokenNode; +import midend.llvm.IrBuilder; +import midend.llvm.constant.IrConstantInt; +import midend.llvm.instr.AluInstr; +import midend.llvm.instr.BranchInstr; +import midend.llvm.instr.CallInstr; +import midend.llvm.instr.CmpInstr; +import midend.llvm.instr.ExtendInstr; +import midend.llvm.instr.GepInstr; +import midend.llvm.instr.GetIntInstr; +import midend.llvm.instr.LoadInstr; +import midend.llvm.type.IrInterType; +import midend.llvm.type.IrType; +import midend.llvm.value.IrBasicBlock; +import midend.llvm.value.IrFuncValue; +import midend.llvm.value.IrValue; +import midend.symbol.*; + +public class VisitorExp { + public static IrValue visitExp(Exp exp) { + return visitAddExp((AddExp) exp.getChild(0)); + } + + public static IrValue visitAddExp(AddExp addExp) { + if (addExp.getChildren().size() == 1) { + return visitMulExp((MulExp) addExp.getChild(0)); + } else { + IrValue left = visitAddExp((AddExp) addExp.getChild(0)); + TokenNode op = (TokenNode) addExp.getChild(1); + IrValue right = visitMulExp((MulExp) addExp.getChild(2)); + left = IrType.convertType(left, IrInterType.INT32); + right = IrType.convertType(right, IrInterType.INT32); + AluInstr aluInstr = new AluInstr(IrBuilder.getLocalName(), op.getValue(), left, right); + IrBuilder.addInstr(aluInstr); + return aluInstr; + } + } + + public static IrValue visitMulExp(MulExp mulExp) { + if (mulExp.getChildren().size() == 1) { + return visitUnaryExp((UnaryExp) mulExp.getChild(0)); + } else { + IrValue left = visitMulExp((MulExp) mulExp.getChild(0)); + TokenNode op = (TokenNode) mulExp.getChild(1); + IrValue right = visitUnaryExp((UnaryExp) mulExp.getChild(2)); + left = IrType.convertType(left, IrInterType.INT32); + right = IrType.convertType(right, IrInterType.INT32); + AluInstr aluInstr = new AluInstr(IrBuilder.getLocalName(), op.getValue(), left, right); + IrBuilder.addInstr(aluInstr); + return aluInstr; + } + } + + public static IrValue visitUnaryExp(UnaryExp unaryExp) { + if (unaryExp.getChild(0) instanceof PrimaryExp) { + return visitPrimaryExp((PrimaryExp) unaryExp.getChild(0)); + } else if (unaryExp.getChild(0) instanceof TokenNode) { + return visitFuncCall((TokenNode) unaryExp.getChild(0), unaryExp.getParamList()); + } else { + return visitOpUnaryExp((UnaryOp) unaryExp.getChild(0), (UnaryExp) unaryExp.getChild(1)); + } + } + + public static IrValue visitOpUnaryExp(UnaryOp uop, UnaryExp unaryExp) { + String op = ((TokenNode) uop.getChild(0)).getValue(); + IrValue operand = visitUnaryExp(unaryExp); + IrConstantInt zero = new IrConstantInt(0); + if (op.equals("+")) { + return operand; + } else if (op.equals("-")) { + AluInstr aluInstr = new AluInstr(IrBuilder.getLocalName(), op, zero, operand); + IrBuilder.addInstr(aluInstr); + return aluInstr; + } else { + operand = IrType.convertType(operand, IrInterType.INT32); + CmpInstr cmpInstr = new CmpInstr(IrBuilder.getLocalName(), "==", zero, operand); + IrBuilder.addInstr(cmpInstr); + ExtendInstr extendInstr = new ExtendInstr( + IrBuilder.getLocalName(), IrInterType.INT32, cmpInstr); + IrBuilder.addInstr(extendInstr); + return extendInstr; + } + } + + public static IrValue visitPrimaryExp(PrimaryExp primaryExp) { + if (primaryExp.getChild(0) instanceof TokenNode) { + return visitExp((Exp) primaryExp.getChild(1)); + } else if (primaryExp.getChild(0) instanceof LVal) { + return visitLVal((LVal) primaryExp.getChild(0), false); + } else { + return new IrConstantInt(((NumberExp) primaryExp.getChild(0)).getValue()); + } + } + + public static IrValue visitFuncCall(TokenNode funcName, ArrayList paramList) { + if (funcName.getValue().equals("getint")) { + GetIntInstr getIntInstr = new GetIntInstr(IrBuilder.getLocalName()); + IrBuilder.addInstr(getIntInstr); + return getIntInstr; + } + FuncSymbol funcSymbol = (FuncSymbol) SymbolManager.getSymbol(funcName.getName(), true); + IrFuncValue irFunction = (IrFuncValue) funcSymbol.getIrValue(); + ArrayList args = new ArrayList<>(); + for (Exp param : paramList) { + args.add(visitExp(param)); + } + CallInstr callInstr = new CallInstr(IrBuilder.getLocalName(), irFunction, args); + IrBuilder.addInstr(callInstr); + return callInstr; + } + + public static IrValue visitLVal(LVal lval, boolean assign) { + if (assign) { + Symbol symbol = SymbolManager.getSymbol(((TokenNode) lval.getChild(0)).getName(), true); + if (!(symbol instanceof ArraySymbol)) { + return symbol.getIrValue(); + } else { + Exp exp = (Exp) lval.getChild(2); + IrValue pointer = symbol.getIrValue(); + GepInstr gepInstr = new GepInstr( + pointer, visitExp(exp), IrBuilder.getLocalName()); + IrBuilder.addInstr(gepInstr); + return gepInstr; + } + } else { + Symbol symbol = SymbolManager.getSymbol(((TokenNode) lval.getChild(0)).getName(), true); + // if (symbol == null) { + // System.out.println(((TokenNode)lval.getChild(0)).getLine() + " " + + // ((TokenNode)lval.getChild(0)).getValue()); + // SymbolTable table = SymbolManager.getCurrentTable(); + // System.out.println(table.toString()); + // // TODO:报错 + // } + if (!(symbol instanceof ArraySymbol)) { + LoadInstr loadInstr = new LoadInstr(symbol.getIrValue(), IrBuilder.getLocalName()); + IrBuilder.addInstr(loadInstr); + return loadInstr; + } else { + if (lval.getChildren().size() == 1) { + GepInstr gepInstr = new GepInstr( + symbol.getIrValue(), new IrConstantInt(0), IrBuilder.getLocalName()); + IrBuilder.addInstr(gepInstr); + return gepInstr; + } else { + Exp exp = (Exp) lval.getChild(2); + GepInstr gepInstr = new GepInstr( + symbol.getIrValue(), visitExp(exp), IrBuilder.getLocalName()); + IrBuilder.addInstr(gepInstr); + LoadInstr loadInstr = new LoadInstr(gepInstr, IrBuilder.getLocalName()); + IrBuilder.addInstr(loadInstr); + return loadInstr; + } + } + } + } + + // TODO:条件表达式的实现 + public static IrValue visitRelExp(RelExp relExp) { + if (relExp.getChildren().size() == 1) { + return visitAddExp((AddExp) relExp.getChild(0)); + } else { + IrValue left = visitRelExp((RelExp) relExp.getChild(0)); + IrValue right = visitAddExp((AddExp) relExp.getChild(2)); + String op = ((TokenNode) relExp.getChild(1)).getValue(); + left = IrType.convertType(left, IrInterType.INT32); + right = IrType.convertType(right, IrInterType.INT32); + CmpInstr cmpInstr = new CmpInstr(IrBuilder.getLocalName(), op, left, right); + IrBuilder.addInstr(cmpInstr); + return cmpInstr; + } + } + + public static IrValue visitEqExp(EqExp eqExp) { + if (eqExp.getChildren().size() == 1) { + return visitRelExp((RelExp) eqExp.getChild(0)); + } else { + IrValue left = visitEqExp((EqExp) eqExp.getChild(0)); + IrValue right = visitRelExp((RelExp) eqExp.getChild(2)); + String op = ((TokenNode) eqExp.getChild(1)).getValue(); + left = IrType.convertType(left, IrInterType.INT32); + right = IrType.convertType(right, IrInterType.INT32); + CmpInstr cmpInstr = new CmpInstr(IrBuilder.getLocalName(), op, left, right); + IrBuilder.addInstr(cmpInstr); + return cmpInstr; + } + } + + public static IrValue visitLAndExp(LAndExp landExp, + IrBasicBlock trueBlock, IrBasicBlock falseBlock) { + if (landExp.getChildren().size() == 1) { + IrValue eqIrValue = visitEqExp((EqExp) landExp.getChild(0)); + eqIrValue = IrType.convertType(eqIrValue, IrInterType.BOOL); + BranchInstr branchInstr = new BranchInstr( + IrBuilder.getLocalName(), eqIrValue, trueBlock, falseBlock); + IrBuilder.addInstr(branchInstr); + return eqIrValue; + } else { + IrBasicBlock nextBB = new IrBasicBlock( + IrBuilder.getBlockName(), IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(nextBB); + IrValue left = visitLAndExp((LAndExp) landExp.getChild(0), nextBB, falseBlock); + IrBuilder.setCurrentBBlock(nextBB); + IrValue right = visitEqExp((EqExp) landExp.getChild(2)); + right = IrType.convertType(right, IrInterType.BOOL); + BranchInstr branchInstr2 = new BranchInstr( + IrBuilder.getLocalName(), right, trueBlock, falseBlock); + IrBuilder.addInstr(branchInstr2); + return right; + } + } + + public static void visitLOrExp(LOrExp lorExp, IrBasicBlock trueBB, IrBasicBlock falseBB) { + if (lorExp.getChildren().size() == 1) { + IrValue landIrValue = visitLAndExp((LAndExp) lorExp.getChild(0), trueBB, falseBB); + } else { + IrBasicBlock nextBB = new IrBasicBlock( + IrBuilder.getBlockName(), IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(nextBB); + visitLOrExp((LOrExp) lorExp.getChild(0), trueBB, nextBB); + IrBuilder.setCurrentBBlock(nextBB); + IrValue right = visitLAndExp((LAndExp) lorExp.getChild(2), trueBB, falseBB); + } + } + + public static void visitCond(Cond cond, IrBasicBlock trueBB, IrBasicBlock falseBB) { + visitLOrExp((LOrExp) cond.getChild(0), trueBB, falseBB); + } +} + + + + + + + + + + + + + + + + + + diff --git a/midend/visit/VisitorFuncDef.java b/midend/visit/VisitorFuncDef.java new file mode 100644 index 0000000..b6584d1 --- /dev/null +++ b/midend/visit/VisitorFuncDef.java @@ -0,0 +1,80 @@ +package midend.visit; + +import java.util.ArrayList; + +import frontend.ast.block.Block; +import frontend.ast.func.FuncDef; +import frontend.ast.func.MainFuncDef; +import frontend.ast.token.TokenNode; +import midend.llvm.IrBuilder; +import midend.llvm.instr.AllocateInstr; +import midend.llvm.instr.StoreInstr; +import midend.llvm.type.IrInterType; +import midend.llvm.type.IrPointerType; +import midend.llvm.value.IrFuncValue; +import midend.llvm.value.IrValue; + +import midend.symbol.Symbol; +import midend.symbol.FuncSymbol; +import midend.symbol.SymbolManager; + +public class VisitorFuncDef { + public static void visitFuncDef(FuncDef funcDef) { + FuncSymbol funcSymbol = (FuncSymbol) SymbolManager.getSymbol( + ((TokenNode) funcDef.getChild(1)).getName()); + IrInterType returnType = funcSymbol.getReturnType() == 1 + ? IrInterType.INT32 + : IrInterType.VOID; + IrFuncValue funcValue = new IrFuncValue( + IrBuilder.geFuncName(funcSymbol.getName()), returnType); + IrBuilder.addNewFunc(funcValue); + funcSymbol.setIrValue(funcValue); + // 进入函数作用域 + SymbolManager.nextTable(); + // System.out.println("(func)now table: " + SymbolManager.getCurrentTableId());//TODO:debug + ArrayList paramList = funcSymbol.getParamList(); + ArrayList paramSymbolList = funcSymbol.getParamSymbolList(); + ArrayList irParamList = new ArrayList<>(); + for (int i = 0; i < paramList.size(); i++) { + if (paramList.get(i) == 0) { + IrValue param = new IrValue(IrInterType.INT32, IrBuilder.getLocalName()); + irParamList.add(param); + funcValue.addParam(param); + } else { + IrValue param = new IrValue( + new IrPointerType(IrInterType.INT32), IrBuilder.getLocalName()); + irParamList.add(param); + funcValue.addParam(param); + paramSymbolList.get(i).setIrValue(param); + } + } + for (int i = 0; i < irParamList.size(); i++) { + if (paramList.get(i) == 1) { + continue; // 数组参数不分配内存 + } + AllocateInstr allocateInstr = new AllocateInstr( + irParamList.get(i).getType(), IrBuilder.getLocalName()); + IrBuilder.addInstr(allocateInstr); + StoreInstr storeInstr = new StoreInstr(irParamList.get(i), allocateInstr); + IrBuilder.addInstr(storeInstr); + paramSymbolList.get(i).setIrValue(allocateInstr); + } //这里貌似可以不用allocate?函数形参似乎可以直接拿来用? + Block block = (Block) funcDef.getChild(funcDef.getChildren().size() - 1); + VisitorBlock.visitBlock(block); + // TODO:check return? + funcValue.checkReturn(); + SymbolManager.nextTable(); + // System.out.println("(func)now table: " + SymbolManager.getCurrentTableId());//TODO:debug + } + + public static void visitMainFuncDef(MainFuncDef mainFuncDef) { + IrFuncValue mainFuncValue = new IrFuncValue( + IrBuilder.geFuncName("main"), IrInterType.INT32); + IrBuilder.addNewFunc(mainFuncValue); + SymbolManager.nextTable(); + // System.out.println("(mainfunc)now table: " + SymbolManager.getCurrentTableId());//TODO:debug + Block block = (Block) mainFuncDef.getChild(mainFuncDef.getChildren().size() - 1); + VisitorBlock.visitBlock(block); + SymbolManager.nextTable(); + } +} \ No newline at end of file diff --git a/midend/visit/VisitorStmt.java b/midend/visit/VisitorStmt.java new file mode 100644 index 0000000..0eb0d15 --- /dev/null +++ b/midend/visit/VisitorStmt.java @@ -0,0 +1,271 @@ +package midend.visit; + +import java.util.ArrayList; + +import frontend.ast.block.Block; +import frontend.ast.block.ForStmt; +import frontend.ast.block.Stmt; +import frontend.ast.exp.Cond; +import frontend.ast.exp.Exp; +import frontend.ast.exp.LVal; +import frontend.ast.token.TokenNode; +import frontend.lexer.Token; +import midend.symbol.SymbolManager; +import midend.llvm.IrBuilder; +import midend.llvm.constant.IrConstantStr; +import midend.llvm.instr.GetIntInstr; +import midend.llvm.instr.JumpInstr; +import midend.llvm.instr.PutIntInstr; +import midend.llvm.instr.PutStrInstr; +import midend.llvm.instr.ReturnInstr; +import midend.llvm.instr.StoreInstr; +import midend.llvm.type.IrInterType; +import midend.llvm.type.IrType; +import midend.llvm.value.IrBasicBlock; +import midend.llvm.value.IrValue; +import midend.llvm.value.IrLoop; + +public class VisitorStmt { + public static void visitStmt(Stmt stmt) { + if (stmt.getChild(0) instanceof LVal) { + visitAssign(stmt); + } else if (stmt.getChild(0) instanceof Exp + || (stmt.getChild(0) instanceof TokenNode + && ((TokenNode) stmt.getChild(0)).getValue().equals(";"))) { + visitExp(stmt); + } else if (stmt.getChild(0) instanceof Block) { + visitBlock(stmt); + } else if (((TokenNode) stmt.getChild(0)).getValue().equals("if")) { + visitIf(stmt); + } else if (((TokenNode) stmt.getChild(0)).getValue().equals("for")) { + visitFor(stmt); + } else if (((TokenNode) stmt.getChild(0)).getValue().equals("break")) { + visitBreak(stmt); + } else if (((TokenNode) stmt.getChild(0)).getValue().equals("continue")) { + visitContinue(stmt); + } else if (((TokenNode) stmt.getChild(0)).getValue().equals("return")) { + visitReturn(stmt); + } else { + visitPrintf(stmt); + } + } + + public static void visitBlock(Stmt stmt) { + Block block = (Block) stmt.getChild(0); + VisitorBlock.visitBlock(block); + } + + public static void visitExp(Stmt stmt) { + if (stmt.getChild(0) instanceof Exp) { + VisitorExp.visitExp((Exp) stmt.getChild(0)); + } + } + + public static void visitAssign(Stmt stmt) { + if (!stmt.isGetint()) { + LVal lval = (LVal) stmt.getChild(0); + Exp exp = (Exp) stmt.getChild(2); + IrValue lvalIr = VisitorExp.visitLVal(lval, true); + IrValue expIr = VisitorExp.visitExp(exp); + expIr = IrType.convertType(expIr, IrInterType.INT32); + StoreInstr storeInstr = new StoreInstr(expIr, lvalIr); + IrBuilder.addInstr(storeInstr); + } else { + LVal lval = (LVal) stmt.getChild(0); + IrValue lvalIr = VisitorExp.visitLVal(lval, true); + GetIntInstr getIntInstr = new GetIntInstr(IrBuilder.getLocalName()); + IrBuilder.addInstr(getIntInstr); + StoreInstr storeInstr = new StoreInstr(getIntInstr, lvalIr); + IrBuilder.addInstr(storeInstr); + } + } + + public static void visitPrintf(Stmt stmt) { + // System.out.println(((TokenNode)stmt.getChild(0)).getValue());//TODO:debug + String strconst = ((TokenNode) stmt.getChild(2)).getValue(); + ArrayList expList = stmt.getExpList(); + ArrayList expIrList = new ArrayList<>(); + for (Exp exp : expList) { + expIrList.add(VisitorExp.visitExp(exp)); + } + StringBuilder sb = new StringBuilder(); + int expnum = 0; + ArrayList printValue = new ArrayList<>(); + for (int i = 0; i < strconst.length(); i++) { + if (strconst.charAt(i) == '%') { + if (!sb.isEmpty() && !sb.toString().equals("\"")) { + IrConstantStr str = IrBuilder.getCurrentModule().getStr(sb.toString()); + // System.out.println(sb.toString());//TODO:debug + if (str == null) { + str = new IrConstantStr(sb.toString(), IrBuilder.getStrName()); + IrBuilder.addNewStr(str); + } + printValue.add(str); // 修改为到最后统一输出,而不是立即输出 + // PutStrInstr putStrInstr = new PutStrInstr(IrBuilder.getLocalName(), str); + // IrBuilder.addInstr(putStrInstr); + sb.setLength(0); + } else if (sb.toString().equals("\"")) { + sb.setLength(0); + } + IrValue expIr = expIrList.get(expnum++); + expIr = IrType.convertType(expIr, IrInterType.INT32); + printValue.add(expIr); // 修改为到最后统一输出,而不是立即输出 + // PutIntInstr putIntInstr = new PutIntInstr(IrBuilder.getLocalName(), expIr); + // IrBuilder.addInstr(putIntInstr); + i++; + } else { + sb.append(strconst.charAt(i)); + } + } + if (!sb.isEmpty() && !sb.toString().equals("\"")) { + IrConstantStr str = IrBuilder.getCurrentModule().getStr(sb.toString()); + // System.out.println(sb.toString());//TODO:debug + if (str == null) { + str = new IrConstantStr(sb.toString(), IrBuilder.getStrName()); + IrBuilder.addNewStr(str); + } + printValue.add(str); // 修改为到最后统一输出,而不是立即输出 + // PutStrInstr putStrInstr = new PutStrInstr(IrBuilder.getLocalName(), str); + // IrBuilder.addInstr(putStrInstr); + sb.setLength(0); + } + for (IrValue irValue : printValue) { + if (irValue instanceof IrConstantStr) { + PutStrInstr putStrInstr = new PutStrInstr( + IrBuilder.getLocalName(), (IrConstantStr) irValue); + IrBuilder.addInstr(putStrInstr); + } else { + PutIntInstr putIntInstr = new PutIntInstr(IrBuilder.getLocalName(), irValue); + IrBuilder.addInstr(putIntInstr); + } + } + } + + public static void visitReturn(Stmt stmt) { + IrValue retValue = null; + if (stmt.getChild(1) instanceof Exp) { + retValue = VisitorExp.visitExp((Exp) stmt.getChild(1)); + retValue = IrType.convertType(retValue, IrInterType.INT32); + } + ReturnInstr returnInstr = new ReturnInstr(retValue); + IrBuilder.addInstr(returnInstr); + } + + public static void visitIf(Stmt stmt) { + Cond cond = (Cond) stmt.getChild(2); + Stmt ifStmt = (Stmt) stmt.getChild(4); + if (stmt.getChildren().size() == 7) { + IrBasicBlock ifBlock = new IrBasicBlock( + IrBuilder.getBlockName(), IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(ifBlock); + IrBasicBlock elseBlock = new IrBasicBlock( + IrBuilder.getBlockName(), IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(elseBlock); + VisitorExp.visitCond(cond, ifBlock, elseBlock); + // ifblock解析 + IrBuilder.setCurrentBBlock(ifBlock); + VisitorStmt.visitStmt(ifStmt); + IrBasicBlock followBlock = new IrBasicBlock( + IrBuilder.getBlockName(), IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(followBlock); + JumpInstr jumpInstr = new JumpInstr(followBlock); + IrBuilder.addInstr(jumpInstr); + //elseblock解析 + IrBuilder.setCurrentBBlock(elseBlock); + Stmt elseStmt = (Stmt) stmt.getChild(6); + VisitorStmt.visitStmt(elseStmt); + jumpInstr = new JumpInstr(followBlock); + IrBuilder.addInstr(jumpInstr); + //跳转至followblock + IrBuilder.setCurrentBBlock(followBlock); + } else { + IrBasicBlock ifBlock = new IrBasicBlock( + IrBuilder.getBlockName(), IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(ifBlock); + IrBasicBlock followBlock = new IrBasicBlock( + IrBuilder.getBlockName(), IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(followBlock); + VisitorExp.visitCond(cond, ifBlock, followBlock); + IrBuilder.setCurrentBBlock(ifBlock); + VisitorStmt.visitStmt(ifStmt); + JumpInstr jumpInstr = new JumpInstr(followBlock); + IrBuilder.addInstr(jumpInstr); + //跳转至followblock + IrBuilder.setCurrentBBlock(followBlock); + } + } + + public static void visitFor(Stmt stmt) { + IrBasicBlock condBB = new IrBasicBlock(IrBuilder.getBlockName(), + IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(condBB); + IrBasicBlock bodyBB = new IrBasicBlock(IrBuilder.getBlockName(), + IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(bodyBB); + IrBasicBlock stepBB = new IrBasicBlock(IrBuilder.getBlockName(), + IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(stepBB); + IrBasicBlock followBB = new IrBasicBlock(IrBuilder.getBlockName(), + IrBuilder.getCurrentFunc()); + IrBuilder.addNewBB(followBB); + IrLoop loop = new IrLoop(condBB, bodyBB, stepBB, followBB); + IrBuilder.pushLoop(loop); + ForStmt initStmt = stmt.getinitStmt(); + if (initStmt != null) { + VisitorStmt.visitForStmt(initStmt); + } + JumpInstr jumpInstr = new JumpInstr(condBB); + IrBuilder.addInstr(jumpInstr); + IrBuilder.setCurrentBBlock(condBB); + Cond cond = stmt.getCond(); + if (cond != null) { + VisitorExp.visitCond(cond, bodyBB, followBB); + } else { + JumpInstr jumpBody = new JumpInstr(bodyBB); + IrBuilder.addInstr(jumpBody); + } + IrBuilder.setCurrentBBlock(bodyBB); + Stmt bodyStmt = stmt.getBodyStmt(); + VisitorStmt.visitStmt(bodyStmt); + jumpInstr = new JumpInstr(stepBB); + IrBuilder.addInstr(jumpInstr); + IrBuilder.setCurrentBBlock(stepBB); + ForStmt stepStmt = stmt.getStepStmt(); + if (stepStmt != null) { + VisitorStmt.visitForStmt(stepStmt); + } + JumpInstr jumpCond = new JumpInstr(condBB); + IrBuilder.addInstr(jumpCond); + IrBuilder.popLoop(); + IrBuilder.setCurrentBBlock(followBB); + } /*TODO:此处可能还有问题,循环体和条件、步长表达式等可能不在一个符号表,应该修改,应该比较好改,判断一下stmt是否为block再决定是否last + 细想应该不用,如果body是一个block,那visit的时候符号表next,visit完之后符号表还会next,相当于再解析step的时候还是原来的符号表*/ + + public static void visitForStmt(ForStmt stmt) { + ArrayList lvalList = stmt.getLValList(); + ArrayList expList = stmt.getExpList(); + for (int i = 0; i < lvalList.size(); i++) { + LVal lval = lvalList.get(i); + Exp exp = expList.get(i); + IrValue lvalIr = VisitorExp.visitLVal(lval, true); + IrValue expIr = VisitorExp.visitExp(exp); + expIr = IrType.convertType(expIr, IrInterType.INT32); + StoreInstr storeInstr = new StoreInstr(expIr, lvalIr); + IrBuilder.addInstr(storeInstr); + } + } + + public static void visitBreak(Stmt stmt) { + IrLoop loop = IrBuilder.getCurrentLoop(); + IrBasicBlock followBB = loop.getFollowBB(); + JumpInstr jumpInstr = new JumpInstr(followBB); + IrBuilder.addInstr(jumpInstr); + } + + public static void visitContinue(Stmt stmt) { + IrLoop loop = IrBuilder.getCurrentLoop(); + IrBasicBlock stepBB = loop.getStepBB(); + JumpInstr jumpInstr = new JumpInstr(stepBB); + IrBuilder.addInstr(jumpInstr); + } +}