diff --git a/pl0-complier-master/.gitignore b/pl0-complier-master/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..c9de4ef54a308c02dd2e93881597df4f154dd6ae --- /dev/null +++ b/pl0-complier-master/.gitignore @@ -0,0 +1,7 @@ +.idea +.settings +bin +out +.classpath +.project +PL0.iml \ No newline at end of file diff --git a/pl0-complier-master/README.md b/pl0-complier-master/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6be2f1586f70d3fe9132578f86e924efaba5a401 --- /dev/null +++ b/pl0-complier-master/README.md @@ -0,0 +1,15 @@ +# pl0-complier + +## 写在前面 +这是一个使用Java编写的简易的pl0语言编译器,所有的源代码均在src文件中。 + +## 目录结构 +- code:pl0样例代码、pl0样例目标代码、pl0语言翻译规则 +- compiler:主程序、文件IO操作 +- error:编译错误类 +- execute:执行目标代码类 +- lexical:词法分析相关类 +- parsing:语法分析以及生成目标代码相关类 + +## 运行相关 +注意,运行之前需要先确认Main类中源文件路径是否正确。 \ No newline at end of file diff --git a/pl0-complier-master/pl0-complier-master.iml b/pl0-complier-master/pl0-complier-master.iml new file mode 100644 index 0000000000000000000000000000000000000000..9465dd864f0bbf5233af344982a638534a50275d --- /dev/null +++ b/pl0-complier-master/pl0-complier-master.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/pl0-complier-master/src/code/code.pl0code b/pl0-complier-master/src/code/code.pl0code new file mode 100644 index 0000000000000000000000000000000000000000..be825c8d6466f654697212b0946fcd9ccd92bf41 --- /dev/null +++ b/pl0-complier-master/src/code/code.pl0code @@ -0,0 +1,20 @@ +JMP 0 10 +JMP 0 2 +INT 0 3 +LIT 0 1 +STO 0 3 +LIT 0 2 +STO 0 4 +LOD 0 3 +STO 0 5 +OPR 0 0 +INT 0 3 +LIT 0 20 +STO 0 3 +LIT 0 30 +STO 0 4 +LOD 0 3 +LOD 0 4 +STO 0 5 +CAL 0 2 +OPR 0 0 \ No newline at end of file diff --git a/pl0-complier-master/src/code/demo.txt b/pl0-complier-master/src/code/demo.txt new file mode 100644 index 0000000000000000000000000000000000000000..a78a107b41f9aba6f4a20ddc6f221f63ec6b97b3 --- /dev/null +++ b/pl0-complier-master/src/code/demo.txt @@ -0,0 +1,74 @@ +这是pl0语言中所有语句的翻译方式 + +==================== +x := 20 + +LIT 20 +STO level_x address_x +==================== + + +==================== +z := x + y + +LOD level_x address_x +LOD level_y address_y +OPR + +STO level_z address_z +==================== + + +==================== +if x < 20 then +begin +z := x + y; +end; + +LOD level_x address_x +LIT 20 +OPR < +JPC L1 +LOD level_x address_x +LOD level_y address_y +OPR + +STO level_z address_z +L1: ... +==================== + + +==================== +while x < 20 do +begin + x := x + y +end; + +L1: LOD level_x address_x +LIT 20 +OPR < +JPC L2 +LOD level_x address_x +LOD level_y address_y +OPR + +STO level_x address_x +JMP L1 +L2: .... +==================== + + +==================== +procedure test; +begin + z := x + y; +end; + +call test; + +JMP L1 +L2: JMP L3 +L3: LOD level_x address_x +LOD level_y address_y +OPR + +STO level_z address_z +OPR return +L1: CAL L2 +==================== \ No newline at end of file diff --git a/pl0-complier-master/src/code/test.pl0 b/pl0-complier-master/src/code/test.pl0 new file mode 100644 index 0000000000000000000000000000000000000000..efed470a3130d3ec74fe4f5c581773f2e3004bb1 --- /dev/null +++ b/pl0-complier-master/src/code/test.pl0 @@ -0,0 +1,36 @@ +var x, y, z; + +procedure test; +var a, b, c; +begin + a := 5; + b := 7; + c := b * a; +end; + +procedure divide; +var d, e, f; +begin + d := 20; + e := 5; + f := d / e; +end; + +begin + x := 4; + y := 100; + + if x < y then + begin + z := y / x; + y := x + y; + end; + + while x < y do + begin + x := x + z; + end; + + call test; + call divide; +end. \ No newline at end of file diff --git a/pl0-complier-master/src/compiler/Main.java b/pl0-complier-master/src/compiler/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..25798d2cb70180335ca7bb9b1188f3489f8fab3f --- /dev/null +++ b/pl0-complier-master/src/compiler/Main.java @@ -0,0 +1,72 @@ +package compiler; + +import execute.ExecuteCode; +import lexical.LexicalAnalyzer; +import lexical.Token; +import parsing.Code; +import parsing.Declaration; +import parsing.DeclarationTableParser; +import parsing.Parser; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +public class Main { + static String sourcePath = "/src/code/test.pl0"; // 测试代码地址 + static String testPath = "/src/code/code.pl0code"; // 测试目标代码地址 + + public static void main(String[] args) throws IOException { + File directory = new File("");// 参数为空 + String courseFile = directory.getCanonicalPath(); + String sourceCodePath = courseFile + sourcePath; + + System.out.println("\n==========源代码=========="); + String sourceCode = SourceCodeFileReader.readFileContent(sourceCodePath, "\n"); + System.out.println(sourceCode); + + System.out.println("\n==========词法分析后的Token=========="); + ArrayList wordsToken = LexicalAnalyzer.getsym(sourceCode); + for (int a = 0; a < wordsToken.size(); a++) { + System.out.println(a + " " + wordsToken.get(a).toString()); + } + + System.out.println("\n==========声明的引用table表=========="); + ArrayList declarationList = DeclarationTableParser.parse(wordsToken, 0, 3); + for (Declaration declaration : declarationList) { + System.out.println(declaration.toString()); + } + + System.out.println("\n==========翻译成的中间代码=========="); +// ArrayList codeList = importTest(); // 使用测试中间代码 + Parser.init(wordsToken, declarationList); + ArrayList codeList = Parser.getCode(); + for (int a = 0; a < codeList.size(); a++) { + System.out.println(a + " " + codeList.get(a).toString()); + } + + + + System.out.println("\n==========执行代码=========="); + ExecuteCode.execute(codeList); + } + + /** + * 导入测试中间代码 + * @return code list + */ + public static ArrayList importTest() throws IOException { + File directory = new File("");// 参数为空 + String courseFile = directory.getCanonicalPath(); + String testCodePath = courseFile + testPath; + String testCode = SourceCodeFileReader.readFileContent(testCodePath, "\n"); + String[] testCodeLine = testCode.split("\n"); + ArrayList codeList = new ArrayList(); + for (String code : testCodeLine) { + String[] detail = code.split(" "); + Code temp = new Code(detail[0], detail[1], detail[2]); + codeList.add(temp); + } + return codeList; + } +} diff --git a/pl0-complier-master/src/compiler/SourceCodeFileReader.java b/pl0-complier-master/src/compiler/SourceCodeFileReader.java new file mode 100644 index 0000000000000000000000000000000000000000..d55ba58c52b623879cfd568f40b1eac1c69b5e1f --- /dev/null +++ b/pl0-complier-master/src/compiler/SourceCodeFileReader.java @@ -0,0 +1,40 @@ +package compiler; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +class SourceCodeFileReader { + /** + * 读取源程序文件的方法,配合charAt,就成为了作业中的GETCH方法。 + * @param fileName 源程序文件路径 + * @param lineFeed 指定换行字符 + * @return 返回读入的文件内容字符串 + */ + static String readFileContent(String fileName, String lineFeed) { + File file = new File(fileName); + BufferedReader reader = null; + StringBuffer fileStringBuffer = new StringBuffer(); + try { + reader = new BufferedReader(new FileReader(file)); + String tempStr; + while ((tempStr = reader.readLine()) != null) { + fileStringBuffer.append(tempStr + lineFeed); + } + reader.close(); + return fileStringBuffer.toString(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + return fileStringBuffer.toString(); + } +} diff --git a/pl0-complier-master/src/error/PL0Error.java b/pl0-complier-master/src/error/PL0Error.java new file mode 100644 index 0000000000000000000000000000000000000000..a04f10ab282de5ce5320b7783f6a4151e85dd5c6 --- /dev/null +++ b/pl0-complier-master/src/error/PL0Error.java @@ -0,0 +1,30 @@ +package error; + +public class PL0Error { + public static void log(int errorType) { + String[] error = new String[] { + "[0 undefined error]", + "[1 constant definition error] undefined const ident", + "[2 constant definition error] const syntax error", + "[3 constant definition error] undefined var ident", + "[4 constant definition error] var syntax error", + "[5 token error] unknown token", + "[6 procedure error] procedure layer more than 3", + "[7 procedure error] undefined procedure ident", + "[8 ident error] ident syntax error", + "[9 ident error] undefined ident", + "[10 ident parse error] assign ident error", + "[11 if parse error] if syntax error", + "[12 boolean parse error] boolean expression syntax error", + "[13 while parse error] while syntax error", + "[14 begin end parse error] missing . or ;", + "[15 call parse error] missing call ident", + "[16 call parse error] missing ;", + }; + if (errorType < error.length) { + System.out.println(error[errorType]); + } else { + System.out.println(error[0]); + } + } +} diff --git a/pl0-complier-master/src/execute/ExecuteCode.java b/pl0-complier-master/src/execute/ExecuteCode.java new file mode 100644 index 0000000000000000000000000000000000000000..e554a1d79927fef66188fbeb55f72af0f43705a0 --- /dev/null +++ b/pl0-complier-master/src/execute/ExecuteCode.java @@ -0,0 +1,163 @@ +package execute; + +import parsing.Code; + +import java.util.ArrayList; + +/** + * 执行生成的目标代码类 + */ +public class ExecuteCode { + private static final int MAX = 1000; + private static int[] stack = new int[MAX]; // 执行栈 + private static int top = 3; // 栈顶元素位置 + private static int base = 1; // program, base, and top-stack register + private static int programCounter = 0; // 程序计数器 + + + /** + * 执行中间代码 + * + * @param codeList 中间代码列表 + */ + public static void execute(ArrayList codeList) { + stack[1] = 0; + stack[2] = 0; + stack[3] = 0; + + do { + Code code = codeList.get(programCounter++); + int levelDifference = Integer.parseInt(code.getLevelDifference()); + int addressOffset = Integer.parseInt(code.getAddressOffset()); + switch (code.getFunction()) { + case "LIT": + stack[++top] = addressOffset; + break; + case "LOD": + stack[++top] = stack[calculateBase(base, levelDifference) + addressOffset]; + break; + case "STO": + stack[calculateBase(base, levelDifference) + addressOffset] = stack[top]; + System.out.println(stack[top]); + top--; + break; + case "CAL": + stack[top + 1] = calculateBase(base, levelDifference); + stack[top + 2] = base; + stack[top + 3] = programCounter; + base = top + 1; + programCounter = addressOffset; + break; + case "INT": + top += addressOffset; + break; + case "JMP": + programCounter = addressOffset; + break; + case "JPC": + if (stack[top] == 0) { + programCounter = addressOffset; + } + top--; + break; + case "OPR": + handleOperator(code); + break; + } + } while (programCounter > 0 && programCounter < codeList.size()); + } + + /** + * 计算偏移量 + * + * @param currentLevel 当前层级 + * @param levelDiff 层极差 + * @return 正确的地址 + */ + private static int calculateBase(int currentLevel, int levelDiff) { + int address = currentLevel; + for (int a = levelDiff; a > 0; a--){ + address = stack[address]; + } + return address; + } + + /** + * 处理operator的方法 + * 0: return + * 1: 相反数 + * 2: + + * 3: - + * 4: * + * 5: / + * 6: # + * 7: == + * 8: <> + * 9: < + * 10: <= + * 11: > + * 12: >= + * + * @param code 中间代码 + */ + private static void handleOperator(Code code) { + int addressOffset = Integer.parseInt(code.getAddressOffset()); + switch (addressOffset) // operator + { + case 0: + top = base - 1; + programCounter = stack[top + 3]; + base = stack[top + 2]; + break; + case 1: + stack[top] = -stack[top]; + break; + case 2: + top--; + stack[top] += stack[top + 1]; + break; + case 3: + top--; + stack[top] -= stack[top + 1]; + break; + case 4: + top--; + stack[top] *= stack[top + 1]; + break; + case 5: + top--; + if (stack[top + 1] == 0) { + System.out.println("Runtime Error: Divided by zero. Fix it as 1"); + stack[top + 1] = 1; + stack[top] /= stack[top + 1]; + } else { + stack[top] /= stack[top + 1]; + } + break; + case 6: + stack[top] %= 2; + break; + case 7: + top--; + stack[top] = (stack[top] == stack[top + 1]) ? 1 : 0; + break; + case 8: + top--; + stack[top] = (stack[top] != stack[top + 1]) ? 1 : 0; + case 9: + top--; + stack[top] = (stack[top] < stack[top + 1]) ? 1 : 0; + break; + case 10: + top--; + stack[top] = (stack[top] <= stack[top + 1]) ? 1 : 0; + case 11: + top--; + stack[top] = (stack[top] > stack[top + 1]) ? 1 : 0; + break; + case 12: + top--; + stack[top] = (stack[top] >= stack[top + 1]) ? 1 : 0; + } + } +} diff --git a/pl0-complier-master/src/lexical/LexicalAnalyzer.java b/pl0-complier-master/src/lexical/LexicalAnalyzer.java new file mode 100644 index 0000000000000000000000000000000000000000..d35cf4b4b99d314ce4608b691b935999edb154d4 --- /dev/null +++ b/pl0-complier-master/src/lexical/LexicalAnalyzer.java @@ -0,0 +1,163 @@ +package lexical; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * 词法分析类 + * + * @author ZY + */ +public class LexicalAnalyzer { + // 关键字 + private static ArrayList keywords = new ArrayList(Arrays.asList("const", "var", "procedure", + "begin", "end", "if", "then", "call", "while", "do", "read", "write")); + + // 运算符 + private static ArrayList operator = new ArrayList( + Arrays.asList("=", "<>", "<", ">", "<=", ">=", ":=", "+", "-", "*", "/", "#")); + + // 界符 + private static ArrayList delimiters = new ArrayList(Arrays.asList(";", ".", ",", "(", ")")); + + // 过滤掉所有的空格 + private static String filterBlank(String str) { + return str.replace(" ", "").replace("\n", "").replace("\t", ""); + } + + /** + * 判断str中从第index位开始,是否能匹配到target中的某一项,若能,则返回该项,否则返回空,若匹配出多项,以最长的为准 + * + * @param str 输入的字符串 + * @param index 词法分析器扫描到哪一个字符 + * @param target 关键字数组 + * @return 返回匹配的字符 + */ + private static String matchList(String str, int index, ArrayList target) { + ArrayList outputList = new ArrayList(); + for (int a = 0; a < target.size(); a++) { + int endIndex = index + target.get(a).length(); + if (endIndex <= str.length()) { + String tempStr = str.substring(index, endIndex); + if (target.indexOf(tempStr) != -1) { + outputList.add(tempStr); + } + } + } + + if (outputList.size() > 0) { + // 获取最长的字符 + int maxLength = outputList.get(0).length(); + int maxLengthIndex = 0; + for (int a = 0; a < outputList.size(); a++) { + if (outputList.get(a).length() > maxLength) { + maxLength = outputList.get(a).length(); + maxLengthIndex = a; + } + } + return outputList.get(maxLengthIndex); + } + return ""; + } + + /** + * 匹配关键字 + * + * @param str 关键字 + * @param index 扫描到的位置 + * @return 返回匹配的字符 + */ + private static String isKeywords(String str, int index) { + return matchList(str, index, keywords); + } + + /** + * 匹配数字 + * + * @param str 关键字 + * @param index 扫描到的位置 + * @return 返回匹配的字符 + */ + private static String isNumber(String str, int index) { + StringBuilder tempNum = new StringBuilder(); + while (index < str.length() && Character.isDigit(str.charAt(index))) { + tempNum.append(str.charAt(index)); + index++; + } + return tempNum.toString(); + } + + /** + * 匹配运算符 + * + * @param str 关键字 + * @param index 扫描到的位置 + * @return 返回匹配的字符 + */ + private static String isOperator(String str, int index) { + return matchList(str, index, operator); + } + + /** + * 匹配界符 + * + * @param str 关键字 + * @param index 扫描到的位置 + * @return 返回匹配的字符 + */ + private static String isDelimiters(String str, int index) { + return matchList(str, index, delimiters); + } + + /** + * 词法分析函数,也就是作业中要求的GETSYM函数 + * + * @param input 输入的字符串 + * @return 返回Token数组 + */ + public static ArrayList getsym(String input) { + String str = filterBlank(input); + ArrayList wordToken = new ArrayList(); + int index = 0; + StringBuilder temp = new StringBuilder(); // 用于缓存ident字符 + while (index < str.length()) { + String keywords = isKeywords(str, index); + String number = isNumber(str, index); + String operator = isOperator(str, index); + String delimiters = isDelimiters(str, index); + if (keywords.length() != 0) { + if (temp.length() != 0) { + wordToken.add(new Token("IDENT", temp.toString(), "")); + temp = new StringBuilder(); + } + wordToken.add(new Token(keywords.toUpperCase() + "SYM", "", "")); + index += keywords.length(); + } else if (number.length() != 0) { + if (temp.length() != 0) { + wordToken.add(new Token("IDENT", temp.toString(), "")); + temp = new StringBuilder(); + } + wordToken.add(new Token("NUMBER", "", number)); + index += number.length(); + } else if (operator.length() != 0) { + if (temp.length() != 0) { + wordToken.add(new Token("IDENT", temp.toString(), "")); + temp = new StringBuilder(); + } + wordToken.add(new Token("SYM_" + operator, "", "")); + index += operator.length(); + } else if (delimiters.length() != 0) { + if (temp.length() != 0) { + wordToken.add(new Token("IDENT", temp.toString(), "")); + temp = new StringBuilder(); + } + wordToken.add(new Token("SYM_" + delimiters, "", "")); + index += delimiters.length(); + } else { + temp.append(str.charAt(index)); + index++; + } + } + return wordToken; + } +} diff --git a/pl0-complier-master/src/lexical/Token.java b/pl0-complier-master/src/lexical/Token.java new file mode 100644 index 0000000000000000000000000000000000000000..c2973f362559703c3e47446a2146c02393517eef --- /dev/null +++ b/pl0-complier-master/src/lexical/Token.java @@ -0,0 +1,52 @@ +package lexical; + +/** + * 符号类,用于词法分析 + * + * @author ZY + */ +public class Token { + private String sym = ""; + private String id = ""; + private String num = ""; + + public Token(String sym, String id, String num) { + super(); + this.sym = sym; + this.id = id; + this.num = num; + } + + public String getSym() { + return sym; + } + + public void setSym(String sym) { + this.sym = sym; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getNum() { + return num; + } + + public void setNum(String num) { + this.num = num; + } + + @Override + public String toString() { + return "Token{" + + "sym='" + sym + '\'' + + ", id='" + id + '\'' + + ", num='" + num + '\'' + + '}'; + } +} diff --git a/pl0-complier-master/src/parsing/Code.java b/pl0-complier-master/src/parsing/Code.java new file mode 100644 index 0000000000000000000000000000000000000000..e93a44f15fa1675ce5eb3fa91222c0dfd4c0c0aa --- /dev/null +++ b/pl0-complier-master/src/parsing/Code.java @@ -0,0 +1,42 @@ +package parsing; + +public class Code { + private String function; + private String levelDifference; + private String addressOffset; + + public Code(String function, String levelDifference, String addressOffset) { + this.function = function; + this.levelDifference = levelDifference; + this.addressOffset = addressOffset; + } + + public String getFunction() { + return function; + } + + public void setFunction(String function) { + this.function = function; + } + + public String getLevelDifference() { + return levelDifference; + } + + public void setLevelDifference(String levelDifference) { + this.levelDifference = levelDifference; + } + + public String getAddressOffset() { + return addressOffset; + } + + public void setAddressOffset(String addressOffset) { + this.addressOffset = addressOffset; + } + + @Override + public String toString() { + return "\t" + function + "\t\t" + levelDifference + "\t" + addressOffset; + } +} diff --git a/pl0-complier-master/src/parsing/Declaration.java b/pl0-complier-master/src/parsing/Declaration.java new file mode 100644 index 0000000000000000000000000000000000000000..c2c48ff5b85c19a5d7a71a243c61e97fdacd7e0f --- /dev/null +++ b/pl0-complier-master/src/parsing/Declaration.java @@ -0,0 +1,131 @@ +package parsing; + +/** + * 声明的元素类,用于记录程序中声明的不同种类的变量/常量/函数 + * 用于语法分析 + * + * @author ZY + */ +public class Declaration { + private String name = ""; + private String kind = ""; + private String val = ""; + private String level = ""; + private String adr = ""; + private int start = -1; + private int end = -1; + private int codeStartIndex = -1; + + public Declaration(String name, String kind, String val, String level, String adr, int start, int end) { + this.name = name; + this.kind = kind; + this.val = val; + this.level = level; + this.adr = adr; + this.start = start; + this.end = end; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getKind() { + return kind; + } + + public void setKind(String kind) { + this.kind = kind; + } + + public String getVal() { + return val; + } + + public void setVal(String val) { + this.val = val; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public String getAdr() { + return adr; + } + + public void setAdr(String adr) { + this.adr = adr; + } + + public int getStart() { + return start; + } + + public void setStart(int start) { + this.start = start; + } + + public int getEnd() { + return end; + } + + public void setEnd(int end) { + this.end = end; + } + + public int getCodeStartIndex() { + return codeStartIndex; + } + + public void setCodeStartIndex(int codeStartIndex) { + this.codeStartIndex = codeStartIndex; + } + + @Override + public String toString() { + switch (kind) { + case "CONSTANT": + return "Declaration{" + + "name='" + name + '\'' + + ", kind='" + kind + '\'' + + ", val='" + val + '\'' + + '}'; + case "VARIABLE": + return "Declaration{" + + "name='" + name + '\'' + + ", kind='" + kind + '\'' + + ", val='" + val + '\'' + + ", level='" + level + '\'' + + ", adr='" + adr + '\'' + + '}'; + case "PROCEDURE": + return "Declaration{" + + "name='" + name + '\'' + + ", kind='" + kind + '\'' + + ", val='" + val + '\'' + + ", level='" + level + '\'' + + ", start=" + start + + ", end=" + end + + '}'; + default: + return "Declaration{" + + "name='" + name + '\'' + + ", kind='" + kind + '\'' + + ", val='" + val + '\'' + + ", level='" + level + '\'' + + ", adr='" + adr + '\'' + + ", start=" + start + + ", end=" + end + + '}'; + } + } +} diff --git a/pl0-complier-master/src/parsing/DeclarationTableParser.java b/pl0-complier-master/src/parsing/DeclarationTableParser.java new file mode 100644 index 0000000000000000000000000000000000000000..722d222c34cabc510cb34739db205e73a81af20a --- /dev/null +++ b/pl0-complier-master/src/parsing/DeclarationTableParser.java @@ -0,0 +1,165 @@ +package parsing; + +import lexical.Token; +import error.PL0Error; + +import java.util.ArrayList; + +/** + * 生成声明变量表的类 + * 声明变量表就是作业中的TABLE + * + * @author ZY + */ +public class DeclarationTableParser { + private static int tokenListIndex = 0; // 扫描token表用的指针 + private static int initLevel = 0; // 初始深度,即为作业中的BLOCK + private static int initAdr = 3; // 初始地址,即为作业中的DX + private static int procedureCounter = 2; // 给procedure的index + private static ArrayList declarationList = new ArrayList(); // 生成的declaration list + + /** + * 生成declaration list的方法 + * + * @param tokenList token列表 + * @param level 初始深度 + * @param adr 初始地址 + * @return declaration list + */ + public static ArrayList parse(ArrayList tokenList, int level, int adr) { + initLevel = level; + initAdr = adr; + while (tokenListIndex < tokenList.size()) { + switch (tokenList.get(tokenListIndex).getSym()) { + case "CONSTSYM": + constantDefinitionParser(tokenList); + break; + case "VARSYM": + variableDefinitionParser(tokenList, initLevel, initAdr); + break; + case "PROCEDURESYM": + procedureDefinitionParser(tokenList, initLevel); + break; + } + tokenListIndex++; + } + + return declarationList; + } + + /** + * 对const进行语法翻译 + * + * @param tokenList token列表 + */ + private static void constantDefinitionParser(ArrayList tokenList) { + while (tokenListIndex < tokenList.size() - 1) { + tokenListIndex++; + if (tokenList.get(tokenListIndex).getSym().equals("IDENT")) { + // 新建一个常量声明 + String identName = tokenList.get(tokenListIndex).getId(); + Declaration constDeclaration = new Declaration(identName, "CONSTANT", "", "", "", -1, -1); + + // 检测是否对常量进行了赋值 + checkAndAddDeclaration(tokenList, constDeclaration); + + // 若读取到分号,则结束,若读取到逗号,则什么都不做,若读取到其他,则抛异常 + if (tokenList.get(tokenListIndex).getSym().equals("SYM_;")) { + break; + } else if (!tokenList.get(tokenListIndex).getSym().equals("SYM_,")) { + PL0Error.log(2); + break; + } + } else { + PL0Error.log(1); + break; + } + } + } + + /** + * 对var进行语法翻译 + * + * @param tokenList token列表 + */ + private static void variableDefinitionParser(ArrayList tokenList, int level, int adr) { + while (tokenListIndex < tokenList.size() - 1) { + tokenListIndex++; + if (tokenList.get(tokenListIndex).getSym().equals("IDENT")) { + // 新建一个变量声明 + String identName = tokenList.get(tokenListIndex).getId(); + Declaration varDeclaration = new Declaration(identName, "VARIABLE", "", level + "", (adr++) + "", -1, -1); + + // 检测是否对变量进行了赋值 + checkAndAddDeclaration(tokenList, varDeclaration); + + // 若读取到分号,则结束,若读取到逗号,则什么都不做,若读取到其他,则抛异常 + if (tokenList.get(tokenListIndex).getSym().equals("SYM_;")) { + break; + } else if (!tokenList.get(tokenListIndex).getSym().equals("SYM_,")) { + PL0Error.log(4); + break; + } + } else { + PL0Error.log(3); + break; + } + } + } + + /** + * 对procedure进行语法翻译 + * + * @param tokenList token列表 + */ + private static void procedureDefinitionParser(ArrayList tokenList, int level) { + if (tokenListIndex < tokenList.size() - 1) { + tokenListIndex++; + if (tokenList.get(tokenListIndex).getSym().equals("IDENT")) { + String identName = tokenList.get(tokenListIndex).getId(); + Declaration procedureDeclaration = new Declaration(identName, "PROCEDURE", "", level + "", "", tokenListIndex - 1, -1); + declarationList.add(procedureDeclaration); + tokenListIndex++; + + label: + while (tokenListIndex < tokenList.size() - 1) { + // 如果在函数中还有var或者procedure,则递归继续执行 + switch (tokenList.get(tokenListIndex).getSym()) { + case "VARSYM": + variableDefinitionParser(tokenList, level + 1, initAdr); + break; + case "PROCEDURESYM": + if (level < 3) { + procedureDefinitionParser(tokenList, level + 1); + } else { + PL0Error.log(6); + } + break; + case "ENDSYM": + procedureDeclaration.setEnd(tokenListIndex); + break label; + } + tokenListIndex++; + } + } else { + PL0Error.log(7); + } + } + } + + /** + * 检查是否对某个变量/常量进行了赋值,即判断x := 20; + * @param tokenList token列表 + * @param declaration 声明 + */ + private static void checkAndAddDeclaration(ArrayList tokenList, Declaration declaration) { + tokenListIndex++; + if (tokenList.get(tokenListIndex).getSym().equals("SYM_=") && tokenList.get(tokenListIndex + 1).getSym().equals("NUMBER")) { + declaration.setVal(tokenList.get(tokenListIndex + 1).getNum()); + declarationList.add(declaration); + tokenListIndex += 2; + } else { + declarationList.add(declaration); + } + } +} diff --git a/pl0-complier-master/src/parsing/Parser.java b/pl0-complier-master/src/parsing/Parser.java new file mode 100644 index 0000000000000000000000000000000000000000..a156e5cbccd3b20cbc9816b774ae871980076024 --- /dev/null +++ b/pl0-complier-master/src/parsing/Parser.java @@ -0,0 +1,400 @@ +package parsing; + +import error.PL0Error; +import lexical.Token; + +import java.util.ArrayList; + +/** + * 语句分析类,生成目标代码 + * + * @author ZY + */ +public class Parser { + private static int tokenListIndex = 0; // 扫描token表用的指针 + private static ArrayList code = new ArrayList(); // 生成的output list,即为作业中的code数组 + private static int filledId = -1; // 回填用的id + + public static void init(ArrayList tokenList, ArrayList declarationList) { + gen("JMP", "0", "main"); + for (Declaration declaration : declarationList) { + if (declaration.getKind().equals("PROCEDURE")) { + gen("JMP", "0", declaration.getName()); + } + } + for (Declaration declaration : declarationList) { + if (declaration.getKind().equals("PROCEDURE")) { + declaration.setCodeStartIndex(code.size()); + gen("INT", "0", "3"); + parse(tokenList, declarationList, declaration.getStart(), declaration.getEnd()); + gen("OPR", "0", "0"); + } + } + + filledCodeList("main", code.size() + ""); // 回填main函数指令 + gen("INT", "0", "3"); + parse(tokenList, declarationList, declarationList.get(declarationList.size() - 1).getEnd(), tokenList.size()); + gen("OPR", "0", "0"); + + // 回填call中的所有函数地址 + for (Declaration declaration : declarationList) { + if (declaration.getKind().equals("PROCEDURE")) { + filledCodeList(declaration.getName(), declaration.getCodeStartIndex() + ""); + } + } + } + + /** + * 对语句进行翻译,生成code list + * read和write暂时不进行处理(因为不知道怎么处理,demo中也并没有给出io相关的指令) + * + * @param tokenList token列表 + */ + private static void parse(ArrayList tokenList, ArrayList declarationList, int startIndex, int endIndex) { + while (tokenListIndex < endIndex) { + switch (tokenList.get(tokenListIndex).getSym()) { + case "IDENT": + identParser(tokenList, declarationList); + break; + case "BEGINSYM": + beginParser(tokenList, declarationList, startIndex); + break; + case "IFSYM": + ifParser(tokenList, declarationList, startIndex, endIndex); + break; + case "CALLSYM": + callParser(tokenList, declarationList); + break; + case "WHILESYM": + whileParser(tokenList, declarationList, startIndex, endIndex); + break; + } + tokenListIndex++; + } + } + + /** + * 翻译ident,例如 x := x + y 或 x := 20 + * + * @param tokenList token列表 + * @param declarationList 声明table + */ + private static void identParser(ArrayList tokenList, ArrayList declarationList) { + Token left = tokenList.get(tokenListIndex); + int leftIndex = getItemIndexInDeclarationList(left, declarationList); + if (left != null && leftIndex != -1) { + Token equals = getNext(tokenList); + if (equals != null && equals.getSym().equals("SYM_:=")) { + expressionParser(tokenList, declarationList, declarationList.get(leftIndex)); + } else if (equals != null && !(equals.getSym().equals("SYM_,") || equals.getSym().equals("SYM_;"))) { + PL0Error.log(8); + } + } else { + PL0Error.log(9); + } + } + + /** + * 处理赋值时 := 的右半部分,即处理表达式 + * TODO:可简化代码 + * + * @param tokenList token列表 + * @param declarationList 变量声明表 + * @param left := 的左半部分 + */ + private static void expressionParser(ArrayList tokenList, ArrayList declarationList, Declaration left) { + Token first = getNext(tokenList); + int firstIndex = getItemIndexInDeclarationList(first, declarationList); + if (first != null && firstIndex != -1 && first.getSym().equals("IDENT")) { + Token next = getNext(tokenList); + if (next != null && next.getSym().equals("SYM_+")) { + // 如 x := x + y; + generateOperatorCode(tokenList, declarationList, left, firstIndex, "2"); + } else if (next != null && next.getSym().equals("SYM_-")) { + // 如 x := x - y + generateOperatorCode(tokenList, declarationList, left, firstIndex, "3"); + } else if (next != null && next.getSym().equals("SYM_*")) { + // 如 x := x * y + generateOperatorCode(tokenList, declarationList, left, firstIndex, "4"); + } else if (next != null && next.getSym().equals("SYM_/")) { + // 如 x := x / y + generateOperatorCode(tokenList, declarationList, left, firstIndex, "5"); + } else if (next != null && next.getSym().equals("SYM_;")) { + // 如 x := y; + gen("LOD", declarationList.get(firstIndex).getLevel(), declarationList.get(firstIndex).getAdr()); + gen("STO", left.getLevel(), left.getAdr()); + } else { + PL0Error.log(10); + } + } else if (first != null && first.getSym().equals("NUMBER")) { + // 如 x := 20; + gen("LIT", "0", first.getNum()); + gen("STO", left.getLevel(), left.getAdr()); + } else { + PL0Error.log(9); + } + } + + /** + * 翻译call + * + * @param tokenList token列表 + * @param declarationList 声明列表 + */ + private static void callParser(ArrayList tokenList, ArrayList declarationList) { + Token ident = getNext(tokenList); + int identIndex = getItemIndexInDeclarationList(ident, declarationList); + if (ident != null && ident.getSym().equals("IDENT")) { + Token end = getNext(tokenList); + if (end != null && end.getSym().equals("SYM_;")) { + if (identIndex != -1) { + gen("CAL", declarationList.get(identIndex).getLevel(), declarationList.get(identIndex).getName()); + } + } else { + PL0Error.log(16); + } + } else { + PL0Error.log(15); + } + } + + private static void beginParser(ArrayList tokenList, ArrayList declarationList, int startIndex) { + int endIndex = findEnd(tokenList, tokenListIndex); + while (tokenListIndex < endIndex) { + Token next = getNext(tokenList); + if (next != null && next.getSym().equals("ENDSYM")) { + Token end = getNext(tokenList); + if (end != null && (end.getSym().equals("SYM_.") || end.getSym().equals("SYM_;"))) { + gen("OPR", "0", "0"); + return; + } else { + PL0Error.log(14); + } + } else { + parse(tokenList, declarationList, startIndex, endIndex); + } + } + } + + /** + * 翻译if + * + * @param tokenList token列表 + * @param declarationList 声明列表 + */ + private static void ifParser(ArrayList tokenList, ArrayList declarationList, int startIndex, int endIndex) { + Token left = getNext(tokenList); + Token operator = getNext(tokenList); + Token right = getNext(tokenList); + Token then = getNext(tokenList); + if (left != null && operator != null && right != null && then != null && then.getSym().equals("THENSYM")) { + booleanParser(left, right, operator, declarationList); + + Token next = getNext(tokenList); + if (next != null && next.getSym().equals("BEGINSYM")) { + int tempKey = --filledId; + gen("JPC", "0", tempKey + ""); + beginParser(tokenList, declarationList, startIndex); + filledCodeList(tempKey + "", code.size() + ""); + } else { + PL0Error.log(11); + } + } else { + PL0Error.log(11); + } + } + + /** + * 翻译while + * + * @param tokenList token列表 + * @param declarationList 声明列表 + */ + private static void whileParser(ArrayList tokenList, ArrayList declarationList, int startIndex, int endIndex) { + Token left = getNext(tokenList); + Token operator = getNext(tokenList); + Token right = getNext(tokenList); + Token doIdent = getNext(tokenList); + if (left != null && operator != null && right != null && doIdent != null && doIdent.getSym().equals("DOSYM")) { + int loopStartPosition = code.size(); + booleanParser(left, right, operator, declarationList); + + Token next = getNext(tokenList); + if (next != null && next.getSym().equals("BEGINSYM")) { + int tempKey = --filledId; + gen("JPC", "0", filledId + ""); + beginParser(tokenList, declarationList, startIndex); + gen("JMP", "0", loopStartPosition + ""); + filledCodeList(tempKey + "", code.size() + ""); + } else { + PL0Error.log(13); + } + } else { + PL0Error.log(13); + } + } + + /** + * 翻译布尔表达式,如 x < y + * + * @param left 左面的元素 + * @param right 右面的元素 + * @param operator 操作符 + * @param declarationList 声明列表 + */ + private static void booleanParser(Token left, Token right, Token operator, ArrayList declarationList) { + booleanItemParser(left, declarationList); + booleanItemParser(right, declarationList); + switch (operator.getSym()) { + case "SYM_==": + gen("OPR", "0", "7"); + break; + case "SYM_<>": + gen("OPR", "0", "8"); + break; + case "SYM_<": + gen("OPR", "0", "9"); + break; + case "SYM_<=": + gen("OPR", "0", "10"); + break; + case "SYM_>": + gen("OPR", "0", "11"); + break; + case "SYM_>=": + gen("OPR", "0", "12"); + break; + } + } + + /** + * 翻译布尔表达式中的某一项 + * + * @param token 某一个token + * @param declarationList 声明列表 + */ + private static void booleanItemParser(Token token, ArrayList declarationList) { + if (token.getSym().equals("IDENT")) { + int index = getItemIndexInDeclarationList(token, declarationList); + if (index != -1) { + gen("LOD", declarationList.get(index).getLevel(), declarationList.get(index).getAdr()); + } else { + PL0Error.log(9); + } + } else if (token.getSym().equals("NUMBER")) { + gen("LIT", "0", token.getNum()); + } else { + PL0Error.log(12); + } + } + + /** + * 根据操作符生成目标代码 + * + * @param tokenList token列表 + * @param declarationList 声明列表 + * @param left 操作符左面的声明 + * @param firstIndex :=左面的声明 + * @param offset 操作符的偏移量 + */ + private static void generateOperatorCode(ArrayList tokenList, ArrayList declarationList, Declaration left, int firstIndex, String offset) { + Token second = getNext(tokenList); + int secondIndex = getItemIndexInDeclarationList(second, declarationList); + Token end = getNext(tokenList); + if (second != null && end != null && end.getSym().equals("SYM_;")) { + gen("LOD", declarationList.get(firstIndex).getLevel(), declarationList.get(firstIndex).getAdr()); + gen("LOD", declarationList.get(secondIndex).getLevel(), declarationList.get(secondIndex).getAdr()); + gen("OPR", "0", offset); + gen("STO", left.getLevel(), left.getAdr()); + } + } + + /** + * 回填数组 + * + * @param key 占位数值 + * @param value 回填的数值 + */ + private static void filledCodeList(String key, String value) { + for (Code item : code) { + if (item.getAddressOffset().equals(key)) { + item.setAddressOffset(value); + } + } + } + + /** + * 获取下一个token + * + * @param tokenList token列表 + * @return token + */ + private static Token getNext(ArrayList tokenList) { + if (tokenListIndex < tokenList.size() - 1) { + tokenListIndex++; + return tokenList.get(tokenListIndex); + } else { + return null; + } + } + + /** + * 判断某个token是否已经在declaration list中声明 + * + * @param token token + * @param declarationList 声明列表 + * @return 如果有,返回index,若没有,返回-1 + */ + private static int getItemIndexInDeclarationList(Token token, ArrayList declarationList) { + for (int a = 0; a < declarationList.size(); a++) { + if (token.getId().equals(declarationList.get(a).getName())) { + return a; + } + } + return -1; + } + + /** + * 将翻译好的功能码加入code数组中 + * + * @param function 功能码 + * @param levelDifference 层次差 + * @param addressOffset 位移量 + */ + private static void gen(String function, String levelDifference, String addressOffset) { + if (levelDifference.equals("")) { + levelDifference = "0"; + } + if (addressOffset.equals("")) { + addressOffset = "0"; + } + Code addCode = new Code(function, levelDifference, addressOffset); + code.add(addCode); + } + + /** + * 匹配与当前begin对应的end + * + * @param tokenArrayList token列表 + * @param index begin的位置 + * @return 对应的end的位置 + */ + private static int findEnd(ArrayList tokenArrayList, int index) { + int begin = 1; + for (int a = index + 1; a < tokenArrayList.size(); a++) { + if (tokenArrayList.get(a).getSym().equals("BEGINSYM")) { + begin++; + } else if (tokenArrayList.get(a).getSym().equals("ENDSYM")) { + begin--; + if (begin == 0) { + return a; + } + } + } + return 0; + } + + public static ArrayList getCode() { + return code; + } +}