From f8a1eefc21bb6285fcccaca52fc2f69e1a24f86d Mon Sep 17 00:00:00 2001 From: D-j001 <3434779743@qq.com> Date: Thu, 20 Dec 2018 22:12:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E5=A4=87=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lexer.c | Bin 125 -> 42 bytes res/SimpleGrammar.txt | 25 ++++++++-- res/lexer.c | 2 +- .../BytecodeGenerator.java | 12 +++-- .../IntermediateCodeGeneration/Compiler.java | 10 ++-- .../ComputClass.java | 10 ++-- src/com/compiler/Main.java | 24 +++++----- src/com/compiler/asm/AsmTest.java | 43 ++++++++++++++++++ src/com/compiler/asm/Instruction.java | 7 +++ src/com/compiler/asm/VariableDeclaration.java | 13 ++++++ src/com/compiler/lexer/LexerTester.java | 4 +- src/com/compiler/parser/ParserGenerator.java | 28 ++++++++---- src/com/compiler/parser/ParserTest.java | 20 ++++---- src/com/compiler/parser/Quaternary.java | 15 ++++++ src/com/compiler/parser/Symbol.java | 17 ++++--- src/com/compiler/parser/SymbolString.java | 20 +++++++- src/com/compiler/parser/Tables.java | 11 ++++- 17 files changed, 202 insertions(+), 59 deletions(-) create mode 100644 src/com/compiler/asm/AsmTest.java create mode 100644 src/com/compiler/asm/Instruction.java create mode 100644 src/com/compiler/asm/VariableDeclaration.java diff --git a/lexer.c b/lexer.c index 0980e8242c30b55983bbb7bc95eb0df6a86b87fb..814ac7e6005be1942a88be2f9de0d9a4142c736d 100644 GIT binary patch literal 42 ocmd1ID^W;PuvIWLw&uzNvXek;0|N*r*_taE$WK(zR!Fi20P1%NZvX%Q literal 125 zcmX^0Z`VEs1_l!b4n_uc-%974#NuLh21Z5(fvm)`ME#t^ymWp4q^#8B5_Se=Mh2GL z#LPTK1~H9jAB22xNl|8Ay0vB)P~JH|C6z&ufr)_yXet8(BLgP`D+3#lW(V?k!6HD> JjUYJ&1^}c^7(@U7 diff --git a/res/SimpleGrammar.txt b/res/SimpleGrammar.txt index 2b8f2df..5f9631b 100644 --- a/res/SimpleGrammar.txt +++ b/res/SimpleGrammar.txt @@ -1,14 +1,30 @@ -program->declear program|calculation ; program|$ +program->declear program|calculation ; program|condition program|cycle program|array_declear program|$ declear->type_name PUSH IDENTIFIER PUSH declear1 declear1->; FILL|= declear2 declear2->CONSTANT PUSH FILL_I ;|IDENTIFIER PUSH FILL_I ; +array_declear->[ CONSTANT PUSH_CAPACITY ] type_name PUSH IDENTIFIER array_declear1 +array_declear1->; FILL_EMPTY_ARRAY|= array_declear2 +array_declear2->{ constant_list } FILL_ARRAY ; + +constant_list->CONSTANT PUSH constant_list1|$ +constant_list1->$|, constant_list + assignment->IDENTIFIER = CONSTANT -calculation->fourth calculation1 -calculation1->fourth_operator PUSH fourth GEQ calculation1|$ +condition->IF ( calculation ) GEQ_IF { program } condition_else END_IF +condition_else->BEGIN_ELSE ELSE { program }|$ + +cycle->WHILE ( calculation ) GEQ_WHILE { program } END_WHILE + + + +calculation->fifth calculation1 +calculation1->fifth_operator PUSH fifth GEQ calculation1 |$ +fifth->fourth fifth1 +fifth1->fourth_operator PUSH fourth GEQ fifth1|$ fourth->third fourth1 fourth1->third_operator PUSH third GEQ fourth1|$ third->second third1 @@ -23,4 +39,5 @@ binary_operator->*|+|-|/|%|&|~|^|| first_operator->!|~ second_operator->*|/|% third_operator->+|-|<<|>> -fourth_operator->&|^|| \ No newline at end of file +fourth_operator->&|^|| +fifth_operator->=|EQ_OP|NE_OP \ No newline at end of file diff --git a/res/lexer.c b/res/lexer.c index 4acc5b6..814ac7e 100644 --- a/res/lexer.c +++ b/res/lexer.c @@ -1,4 +1,4 @@ int a = 13; -int b = 16; +int b = 100; int c; c = a + b; \ No newline at end of file diff --git a/src/com/compiler/IntermediateCodeGeneration/BytecodeGenerator.java b/src/com/compiler/IntermediateCodeGeneration/BytecodeGenerator.java index 8622ea0..99b0d86 100644 --- a/src/com/compiler/IntermediateCodeGeneration/BytecodeGenerator.java +++ b/src/com/compiler/IntermediateCodeGeneration/BytecodeGenerator.java @@ -1,14 +1,14 @@ package com.compiler.IntermediateCodeGeneration; import com.compiler.parser.Quaternary; +import com.compiler.parser.Tables; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -import java.util.ArrayList; - public class BytecodeGenerator implements Opcodes { - public byte[] generateBytecode(ArrayList array) throws Exception { + public byte[] generateBytecode() throws Exception { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); MethodVisitor mv; //版本 ,类型, 名字, signature,父类, 接口 @@ -18,9 +18,11 @@ public class BytecodeGenerator implements Opcodes { //声明 static void main mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); //遍历四元式 - for (Quaternary quaternary : array) { + System.out.println(Tables.quaternaryList + "!!!"); + for (Quaternary quaternary : Tables.quaternaryList) { ComputClass c = new ComputClass(new Quaternary()); - c.comput(mv); + c.comput(mv,quaternary); + System.out.println("循环四元式完成"); } mv.visitInsn(RETURN); //add return instruction mv.visitEnd(); diff --git a/src/com/compiler/IntermediateCodeGeneration/Compiler.java b/src/com/compiler/IntermediateCodeGeneration/Compiler.java index 1e06a6b..4d9728b 100644 --- a/src/com/compiler/IntermediateCodeGeneration/Compiler.java +++ b/src/com/compiler/IntermediateCodeGeneration/Compiler.java @@ -1,6 +1,5 @@ package com.compiler.IntermediateCodeGeneration; -import com.compiler.parser.Tables; import org.apache.commons.lang3.StringUtils; import org.objectweb.asm.Opcodes; @@ -10,17 +9,18 @@ import java.io.IOException; import java.io.OutputStream; public class Compiler implements Opcodes { - public void Compilermain(String[] args) throws Exception { + /*public void Compilermain(String[] args) throws Exception { new Compiler().compile(args); - } + }*/ - public void compile(String[] args) throws Exception { + public void compile() throws Exception { + //System.out.println(Tables.quaternaryList + "!!!"); final File enkelFile = new File("res/lexer.c"); String fileName = enkelFile.getName(); //String fileAbsolutePath = enkelFile.getAbsolutePath(); //String className = StringUtils.remove(fileName, ".enk"); - final byte[] byteCode = new BytecodeGenerator().generateBytecode(Tables.quaternaryList); + final byte[] byteCode = new BytecodeGenerator().generateBytecode(); saveBytecodeToClassFile(fileName, byteCode); } diff --git a/src/com/compiler/IntermediateCodeGeneration/ComputClass.java b/src/com/compiler/IntermediateCodeGeneration/ComputClass.java index ec9a650..3e0f571 100644 --- a/src/com/compiler/IntermediateCodeGeneration/ComputClass.java +++ b/src/com/compiler/IntermediateCodeGeneration/ComputClass.java @@ -15,15 +15,16 @@ public class ComputClass implements Opcodes { this.quaternary = quaternary; } - public void comput(MethodVisitor mv){ - final String opt = quaternary.getOpt();//判断运算符 - if (opt == "=") { + public void comput(MethodVisitor mv , Quaternary quaternary){ + final String opt = new String(quaternary.getOpt());//判断运算符 + if (opt.equals("=")) { switch (Tables.getType(quaternary.getOpds().get(0))){ case INTEGER: int val0 = Tables.getSymbolCount(quaternary.getOpds().get(0), TypeLabelItem.type.INTEGER); int val2 = Tables.getSymbolCount(quaternary.getOpds().get(2), TypeLabelItem.type.INTEGER); mv.visitIntInsn(BIPUSH, val0); mv.visitVarInsn(ISTORE, val2); + System.out.println("等于完成"); break; case FLOAT: int dou0 = Tables.getSymbolCount(quaternary.getOpds().get(0), TypeLabelItem.type.FLOAT); @@ -34,7 +35,7 @@ public class ComputClass implements Opcodes { } } - else if(opt == "+"){ + else if(opt.equals("+")){ switch (Tables.getType(quaternary.getOpds().get(0))){ case INTEGER: int val0 = Tables.getSymbolCount(quaternary.getOpds().get(0), TypeLabelItem.type.INTEGER); @@ -44,6 +45,7 @@ public class ComputClass implements Opcodes { mv.visitVarInsn(ILOAD, val1); mv.visitInsn(IADD); mv.visitVarInsn(ISTORE, val2); + System.out.println("加法完成"); break; case FLOAT: int dou0 = Tables.getSymbolCount(quaternary.getOpds().get(0), TypeLabelItem.type.FLOAT); diff --git a/src/com/compiler/Main.java b/src/com/compiler/Main.java index 64a0b79..0f982d0 100644 --- a/src/com/compiler/Main.java +++ b/src/com/compiler/Main.java @@ -1,40 +1,40 @@ package com.compiler; -import com.compiler.lexer.Lexer; +import com.compiler.IntermediateCodeGeneration.Compiler; import com.compiler.lexer.LexerTester; import com.compiler.parser.ParserGenerator; import com.compiler.parser.ParserTest; import com.compiler.parser.Tables; -import com.compiler.parser.Test; -import com.compiler.utils.FileReader; -import com.compiler.utils.Show; - -import java.util.ArrayList; -import java.util.List; public class Main { public static void main(String[] args) { + System.out.println("===================================="); + + LexerTester lt = new LexerTester(); var tokenList = lt.getTokenList(); System.out.println(tokenList); - System.out.println("========="); + System.out.println("===================================="); ParserTest pt = new ParserTest(); var symbolString = ParserGenerator.ReadTokenlist(tokenList); System.out.println(symbolString); + boolean result = pt.Check(symbolString); + var compiler = new Compiler(); + try{compiler.compile();} + catch (Exception e){ + e.printStackTrace(); + } System.out.println(result); System.out.println(Tables.SymbolTable); + System.out.println(Tables.quaternaryList); -// List lines = FileReader.getLines("res/SimpleGrammar.txt"); -////// lines.add("primary_expression->IDENTIFIER|CONSTANT|STRING_LITERAL|( expression )"); -////// lines.add("B->tc|ee"); -// Show.printRules(ParserGenerator.Read(lines)); } } diff --git a/src/com/compiler/asm/AsmTest.java b/src/com/compiler/asm/AsmTest.java new file mode 100644 index 0000000..7d4e3c6 --- /dev/null +++ b/src/com/compiler/asm/AsmTest.java @@ -0,0 +1,43 @@ +package com.compiler.asm; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.Queue; + +public class AsmTest { + public static void compile(){ + class BytecodeGenerator implements Opcodes{ + public byte[] generateBytecode(Queue instructionQueue, String name) throws Exception { + + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + //version , acess, name, signature, base class, interfaes + cw.visit(52, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null); + { + //declare static void main + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); + final long localVariablesCount = instructionQueue.stream() + .filter(instruction -> instruction instanceof VariableDeclaration) + .count(); + final int maxStack = 100; //TODO - do that properly + + //apply instructions generated from traversing parse tree! + for (Instruction instruction : instructionQueue) { + instruction.apply(mv); + } + mv.visitInsn(RETURN); //add return instruction + + mv.visitMaxs(maxStack, (int) localVariablesCount); //set max stack and max local variables + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } + } + + } +} + diff --git a/src/com/compiler/asm/Instruction.java b/src/com/compiler/asm/Instruction.java new file mode 100644 index 0000000..81acd33 --- /dev/null +++ b/src/com/compiler/asm/Instruction.java @@ -0,0 +1,7 @@ +package com.compiler.asm; + +import org.objectweb.asm.MethodVisitor; + +public interface Instruction { + void apply(MethodVisitor methodVisitor); +} diff --git a/src/com/compiler/asm/VariableDeclaration.java b/src/com/compiler/asm/VariableDeclaration.java new file mode 100644 index 0000000..dbe3ebc --- /dev/null +++ b/src/com/compiler/asm/VariableDeclaration.java @@ -0,0 +1,13 @@ +package com.compiler.asm; + +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class VariableDeclaration implements Instruction, Opcodes { +// Variable variable; + + @Override + public void apply(MethodVisitor methodVisitor) { + + } +} diff --git a/src/com/compiler/lexer/LexerTester.java b/src/com/compiler/lexer/LexerTester.java index 778b5df..f41def1 100644 --- a/src/com/compiler/lexer/LexerTester.java +++ b/src/com/compiler/lexer/LexerTester.java @@ -79,8 +79,8 @@ public class LexerTester { } private boolean isKeywordSuffix(Character ch) { - return ch == ')' || ch == ' ' || ch == '\t' - || ch == '[' || ch == '*'; + return ch=='(' || ch == ')' || ch == ' ' || ch == '\t' + || ch == '[' || ch == '*' || ch=='{'; } private boolean isNumSuffix(Character ch) { diff --git a/src/com/compiler/parser/ParserGenerator.java b/src/com/compiler/parser/ParserGenerator.java index 32f135a..c037e40 100644 --- a/src/com/compiler/parser/ParserGenerator.java +++ b/src/com/compiler/parser/ParserGenerator.java @@ -2,7 +2,6 @@ package com.compiler.parser; import com.compiler.lexer.Token; -import javax.lang.model.util.ElementScanner6; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -36,13 +35,29 @@ public class ParserGenerator { if (sym.equals("$")) symbolString.add(new Symbol(sym, Symbol.SymbolType.Empty)); else if (sym.equals("PUSH")) - symbolString.add(new Symbol(sym, Symbol.ActionTYpe.PUSH)); + symbolString.add(new Symbol(sym, Symbol.ActionType.PUSH)); + else if (sym.equals("PUSH_CAPACITY")) + symbolString.add(new Symbol(sym, Symbol.ActionType.PUSH_CAPACITY)); else if (sym.equals("FILL")) - symbolString.add(new Symbol(sym, Symbol.ActionTYpe.FILL)); + symbolString.add(new Symbol(sym, Symbol.ActionType.FILL)); else if (sym.equals("FILL_I")) - symbolString.add(new Symbol(sym, Symbol.ActionTYpe.FILL_I)); + symbolString.add(new Symbol(sym, Symbol.ActionType.FILL_I)); + else if (sym.equals("FILL_ARRAY")) + symbolString.add(new Symbol(sym, Symbol.ActionType.FILL_ARRAY)); + else if (sym.equals("FILL_EMPTY_ARRAY")) + symbolString.add(new Symbol(sym, Symbol.ActionType.FILL_EMPTY_ARRAY)); else if (sym.equals("GEQ")) - symbolString.add(new Symbol(sym, Symbol.ActionTYpe.GEQ)); + symbolString.add(new Symbol(sym, Symbol.ActionType.GEQ)); + else if (sym.equals("GEQ_IF")) + symbolString.add(new Symbol(sym, Symbol.ActionType.GEQ_IF)); + else if (sym.equals("END_IF")) + symbolString.add(new Symbol(sym, Symbol.ActionType.END_IF)); + else if (sym.equals("BEGIN_ELSE")) + symbolString.add(new Symbol(sym, Symbol.ActionType.BEGIN_ELSE)); + else if (sym.equals("GEQ_WHILE")) + symbolString.add(new Symbol(sym, Symbol.ActionType.GEQ_WHILE)); + else if (sym.equals("END_WHILE")) + symbolString.add(new Symbol(sym, Symbol.ActionType.END_WHILE)); else if (ParserTest.isTerminal(sym)) symbolString.add(new Symbol(sym, Symbol.SymbolType.Terminal)); else @@ -70,9 +85,6 @@ public class ParserGenerator { break; case DELIMITER: switch (token.getStr()) { - case "=": - symbolList.add(new Symbol("=", Symbol.SymbolType.Terminal)); - break; case "*=": symbolList.add(new Symbol("MUL_ASSIGN", Symbol.SymbolType.Terminal)); break; diff --git a/src/com/compiler/parser/ParserTest.java b/src/com/compiler/parser/ParserTest.java index a7e7aa0..e0671e5 100644 --- a/src/com/compiler/parser/ParserTest.java +++ b/src/com/compiler/parser/ParserTest.java @@ -26,16 +26,16 @@ public class ParserTest extends LLParser { // System.out.print("\t"); // System.out.println(form.get(k)); // } - var rules = getProductionRules(); - for (var ru : rules.keySet()) { - var strs = rules.get(ru); - for (var st : strs) { - var select = getSelect(st); - System.out.print(st); - System.out.print(": "); - System.out.println(select); - } - } +// var rules = getProductionRules(); +// for (var ru : rules.keySet()) { +// var strs = rules.get(ru); +// for (var st : strs) { +// var select = getSelect(st); +// System.out.print(st); +// System.out.print(": "); +// System.out.println(select); +// } +// } } diff --git a/src/com/compiler/parser/Quaternary.java b/src/com/compiler/parser/Quaternary.java index b9c4e45..7fcdbc3 100644 --- a/src/com/compiler/parser/Quaternary.java +++ b/src/com/compiler/parser/Quaternary.java @@ -26,4 +26,19 @@ public class Quaternary { public ArrayList getOpds() { return new ArrayList(Arrays.asList(opd1, opd2, opd3)); } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("("); + sb.append(opt); + sb.append(", "); + sb.append(opd1); + sb.append(", "); + sb.append(opd2); + sb.append(", "); + sb.append(opd3); + sb.append(")"); + return sb.toString(); + } } diff --git a/src/com/compiler/parser/Symbol.java b/src/com/compiler/parser/Symbol.java index 158b026..69e9910 100644 --- a/src/com/compiler/parser/Symbol.java +++ b/src/com/compiler/parser/Symbol.java @@ -23,7 +23,7 @@ public class Symbol { this.valueType = type; } - Symbol(final String name, ActionTYpe at) { + Symbol(final String name, ActionType at) { id = name; aType = at; sType = SymbolType.Action; @@ -34,10 +34,13 @@ public class Symbol { Terminal, Nonterminal, Empty, End, Action } - enum ActionTYpe { - PUSH, FILL - , FILL_I //有初值的填表 + enum ActionType { + PUSH, FILL, FILL_I //有初值的填表 + , FILL_ARRAY //填数组表 + , FILL_EMPTY_ARRAY //填空数组 + , PUSH_CAPACITY //将数组容量压栈 , GEQ //生成运算四元式 + , GEQ_IF, END_IF, BEGIN_ELSE, GEQ_WHILE, END_WHILE } public String getId() { @@ -48,7 +51,7 @@ public class Symbol { return sType; } - public ActionTYpe getaType() { + public ActionType getaType() { return aType; } @@ -62,7 +65,7 @@ public class Symbol { private String id; private SymbolType sType; - private ActionTYpe aType; + private ActionType aType; private String value; private Token.tokenType valueType = Token.tokenType.NONE; @@ -71,6 +74,8 @@ public class Symbol { StringBuilder sb = new StringBuilder(); if (sType == SymbolType.Nonterminal) sb.append("[N]"); + else if (sType == SymbolType.Action) + sb.append("[AC]"); sb.append(id); if (valueType != Token.tokenType.NONE) { sb.append("("); diff --git a/src/com/compiler/parser/SymbolString.java b/src/com/compiler/parser/SymbolString.java index 01d6580..a5d26c6 100644 --- a/src/com/compiler/parser/SymbolString.java +++ b/src/com/compiler/parser/SymbolString.java @@ -78,7 +78,17 @@ public class SymbolString implements Iterable { boolean isEmpty() { return symString.isEmpty() || - (symString.get(0).getType().equals(Symbol.SymbolType.Empty)); + (symString.get(0).getType().equals(Symbol.SymbolType.Empty)) || + isAllAction(); + + } + + private boolean isAllAction() { + for (var sym : symString) { + if (sym.getType() != Symbol.SymbolType.Action) + return false; + } + return true; } public int size() { @@ -111,4 +121,12 @@ public class SymbolString implements Iterable { private ArrayList symString; private int id; + + public Symbol getFirstSymbol() { + for (var sym : symString) { + if (sym.getType() != Symbol.SymbolType.Action) + return sym; + } + return new Symbol(); + } } diff --git a/src/com/compiler/parser/Tables.java b/src/com/compiler/parser/Tables.java index 82be998..51830c9 100644 --- a/src/com/compiler/parser/Tables.java +++ b/src/com/compiler/parser/Tables.java @@ -21,6 +21,9 @@ public class Tables { public static ArrayList doubleList = new ArrayList<>(); public static ArrayList charList = new ArrayList<>(); + //数组表 + public static ArrayList arrayTable = new ArrayList<>(); + //四元式表 public static ArrayList quaternaryList = new ArrayList<>(); @@ -63,6 +66,7 @@ public class Tables { return ' '; } + // 在符号表中查找名为name的符号并返回其类型,若符号表中不存在该符号则返回NULL类型 public static TypeLabelItem.type getType(String name) { var first = SymbolTable.stream().filter(item -> item.getName().equals(name)).findFirst(); if (first.isPresent()) { @@ -72,6 +76,7 @@ public class Tables { return TypeLabelItem.type.NULL; } + //返回 名为name的符号 是 符号表中第几个 类型为type的 符号 public static int getSymbolCount(String name, TypeLabelItem.type type) { int index = 0; for (SymbolTableItem item : SymbolTable) { @@ -152,6 +157,10 @@ class SymbolTableItem { Tables.integerList.add(Integer.parseInt(initVal)); addr = Tables.integerList.size() - 1; break; + case NONE://其他类型(数组) + typ = Tables.typeTabel.size(); + Tables.typeTabel.add(new TypeLabelItem(TypeLabelItem.type.ARRAY)); + break; } } @@ -203,7 +212,7 @@ class SymbolTableItem { //数组表 class ArrayTableItem { - public ArrayTableItem(int up) { + public ArrayTableItem(int up, Token.tokenType type) { this.up = up; }