一、从Gitee上下载编译器框架的可执行包并解压,可以得到一个jar文件,我们不执行jar文件,而是作为一个模块导入。(https://gitee.com/llyronx/LYRON/attach_files/329927/download)。
二、使用Intellij IDEA新建一个Java工程,然后将lib和jar包移动到工程文件夹下。
三、在Project Structure中设置Dependencies,添加加入的jar文件。
四、新建一个XML文件,写下计算器的基本文法:
<?xml version="1.0" encoding="UTF-8" ?> <pldl> <cfgproductions> <item> <production> Program -> E </production> </item> <item> <production> E -> E + T</production> </item> <item> <production> E -> E - T</production> </item> <item> <production> E -> T </production> </item> <item> <production> T -> T * F</production> </item> <item> <production> T -> T / F</production> </item> <item> <production> T -> F </production> </item> <item> <production> F -> num</production> </item> <item> <production> F -> ( E )</production> </item> </cfgproductions> <terminators> <item> <name>num</name> <regex>[1-9][0-9]*|0</regex> </item> </terminators> <comments></comments> </pldl>
五、完善<movements>:在每个文法产生式增加简单的属性传递动作,其中加减乘除产生式的属性传递动作都相同:
<?xml version="1.0" encoding="UTF-8" ?> <pldl> <cfgproductions> <item> <production> Program -> E </production> <movements> <item>go($1)</item> </movements> </item> <item> <production> E -> E + T</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> </item> <item> <production> E -> E - T</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> </item> <item> <production> E -> T </production> <movements> <item>go($1)</item> <item>$$(val) = $1(val)</item> </movements> </item> <item> <production> T -> T * F</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> </item> <item> <production> T -> T / F</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> </item> <item> <production>T -> F </production> <movements> <item>go($1)</item> <item>$$(val) = $1(val)</item> </movements> </item> <item> <production> F -> num</production> <movements> <item>$$(val) = $1(val)</item> </movements> </item> <item> <production> F -> ( E )</production> <movements> <item>go($2)</item> <item>$$(val) = $2(val)</item> </movements> </item> </cfgproductions> <terminators> <item> <name>num</name> <regex>[1-9][0-9]*|0</regex> </item> </terminators> <comments></comments> </pldl>
六、完善生成四元式的语法动作,只需要在加减乘除产生式和Program产生式中加入<after-generations>即可,其中Program添加的语句用于结束:
<?xml version="1.0" encoding="UTF-8" ?> <pldl> <cfgproductions> <item> <production> Program -> E </production> <movements> <item>go($1)</item> </movements> <after-generations> <item>gen(end, _, _, $1(val))</item> </after-generations> </item> <item> <production> E -> E + T</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> <after-generations> <item>gen(add, $1(val), $3(val), $$(val))</item> </after-generations> </item> <item> <production> E -> E - T</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> <after-generations> <item>gen(sub, $1(val), $3(val), $$(val))</item> </after-generations> </item> <item> <production> E -> T </production> <movements> <item>go($1)</item> <item>$$(val) = $1(val)</item> </movements> </item> <item> <production> T -> T * F</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> <after-generations> <item>gen(multi, $1(val), $3(val), $$(val))</item> </after-generations> </item> <item> <production> T -> T / F</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> <after-generations> <item>gen(div, $1(val), $3(val), $$(val))</item> </after-generations> </item> <item> <production>T -> F </production> <movements> <item>go($1)</item> <item>$$(val) = $1(val)</item> </movements> </item> <item> <production> F -> num</production> <movements> <item>$$(val) = $1(val)</item> </movements> </item> <item> <production> F -> ( E )</production> <movements> <item>go($2)</item> <item>$$(val) = $2(val)</item> </movements> </item> </cfgproductions> <terminators> <item> <name>num</name> <regex>[1-9][0-9]*|0</regex> </item> </terminators> <comments></comments> </pldl>
七、编写测试代码进行测试,注意ConsoleApplication中LLBegin用于初始化XML文件,LLParse用于解析代码文件(在这里则是四则运算式),LLEnd用于输出四元式。
public static void main(String[] args) throws Exception { FileInputStream grammarInput = new FileInputStream(new File("Calculator.xml")); FileOutputStream fourTupleOutput = new FileOutputStream(new File("fourTuple.txt")); StringBufferInputStream codeInput = new StringBufferInputStream("1+2*3"); ConsoleApplication consoleApplication = new ConsoleApplication(); consoleApplication.LLBegin(grammarInput); consoleApplication.LLParse(codeInput); consoleApplication.LLEnd(fourTupleOutput); }
下面是输出结果:
八、最后编写代码解析输出四元式即可,只需要一个简单的符号表(临时变量和数值的映射):
private static int getVar(HashMap<String, Integer> symbols, String s){ return Character.isDigit(s.charAt(0)) ? Integer.valueOf(s) : symbols.get(s); } private static void putVar(HashMap<String, Integer> symbols, String s, Integer i){ symbols.put(s, i); } public static int getResult(InputStream stream){ Scanner scanner = new Scanner(stream); HashMap<String, Integer> symbols = new HashMap<>(); String last = null; while (scanner.hasNext()){ String lineIn = scanner.nextLine(); String []fourStrs = lineIn.split(","); int first, second; switch (fourStrs[0]){ case "add": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first + second); break; case "sub": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first - second); break; case "multi": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first * second); break; case "div": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first / second); break; case "end": return getVar(symbols, fourStrs[3]); } } return 0; }
在main中调用:
public static void main(String[] args) throws Exception { FileInputStream grammarInput = new FileInputStream(new File("Calculator.xml")); FileOutputStream fourTupleOutput = new FileOutputStream(new File("fourTuple.txt")); StringBufferInputStream codeInput = new StringBufferInputStream("1+2*3"); ConsoleApplication consoleApplication = new ConsoleApplication(); consoleApplication.LLBegin(grammarInput); consoleApplication.LLParse(codeInput); consoleApplication.LLEnd(fourTupleOutput); fourTupleOutput.close(); FileInputStream fourTupleInput = new FileInputStream(new File("fourTuple.txt")); System.out.println(getResult(fourTupleInput)); }
运行结果:
附xml文件代码:
<?xml version="1.0" encoding="UTF-8" ?> <pldl> <cfgproductions> <item> <production> Program -> E </production> <movements> <item>go($1)</item> </movements> <after-generations> <item>gen(end, _, _, $1(val))</item> </after-generations> </item> <item> <production> E -> E + T</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> <after-generations> <item>gen(add, $1(val), $3(val), $$(val))</item> </after-generations> </item> <item> <production> E -> E - T</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> <after-generations> <item>gen(sub, $1(val), $3(val), $$(val))</item> </after-generations> </item> <item> <production> E -> T </production> <movements> <item>go($1)</item> <item>$$(val) = $1(val)</item> </movements> </item> <item> <production> T -> T * F</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> <after-generations> <item>gen(multi, $1(val), $3(val), $$(val))</item> </after-generations> </item> <item> <production> T -> T / F</production> <movements> <item>go($1)</item> <item>go($3)</item> <item>$$(val) = newTemp(var)</item> </movements> <after-generations> <item>gen(div, $1(val), $3(val), $$(val))</item> </after-generations> </item> <item> <production>T -> F </production> <movements> <item>go($1)</item> <item>$$(val) = $1(val)</item> </movements> </item> <item> <production> F -> num</production> <movements> <item>$$(val) = $1(val)</item> </movements> </item> <item> <production> F -> ( E )</production> <movements> <item>go($2)</item> <item>$$(val) = $2(val)</item> </movements> </item> </cfgproductions> <terminators> <item> <name>num</name> <regex>[1-9][0-9]*|0</regex> </item> </terminators> <comments></comments> </pldl>
Java代码:
import app.ConsoleApplication; import java.io.*; import java.util.HashMap; import java.util.Scanner; public class Calculator { private static int getVar(HashMap<String, Integer> symbols, String s){ return Character.isDigit(s.charAt(0)) ? Integer.valueOf(s) : symbols.get(s); } private static void putVar(HashMap<String, Integer> symbols, String s, Integer i){ symbols.put(s, i); } public static int getResult(InputStream stream){ Scanner scanner = new Scanner(stream); HashMap<String, Integer> symbols = new HashMap<>(); String last = null; while (scanner.hasNext()){ String lineIn = scanner.nextLine(); String []fourStrs = lineIn.split(","); int first, second; switch (fourStrs[0]){ case "add": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first + second); break; case "sub": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first - second); break; case "multi": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first * second); break; case "div": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first / second); break; case "end": return getVar(symbols, fourStrs[3]); } } return 0; } public static void main(String[] args) throws Exception { FileInputStream grammarInput = new FileInputStream(new File("Calculator.xml")); FileOutputStream fourTupleOutput = new FileOutputStream(new File("fourTuple.txt")); StringBufferInputStream codeInput = new StringBufferInputStream("1+2*3"); ConsoleApplication consoleApplication = new ConsoleApplication(); consoleApplication.LLBegin(grammarInput); consoleApplication.LLParse(codeInput); consoleApplication.LLEnd(fourTupleOutput); fourTupleOutput.close(); FileInputStream fourTupleInput = new FileInputStream(new File("fourTuple.txt")); System.out.println(getResult(fourTupleInput)); } }