软件体系结构的第二次实验(解释器风格与管道过滤器风格)
一、实验目的
1.熟悉体系结构的风格的概念
2.理解和应用管道过滤器型的风格。
3、理解解释器的原理
4、理解编译器模型
二、实验环境
硬件:
软件:Python或任何一种自己喜欢的语言
三、实验内容
1、实现“四则运算”的简易翻译器。
结果要求:
1)实现加减乘除四则运算,允许同时又多个操作数,如:2+3*5-6 结果是11
2)被操作数为整数,整数可以有多位
3)处理空格
4)输入错误显示错误提示,并返回命令状态“CALC”
图1 实验结果示例
加强练习:
1、有能力的同学,可以尝试实现赋值语句,例如x=2+3*5-6,返回x=11。(注意:要实现解释器的功能,而不是只是显示)
2、尝试实现自增和自减符号,例如x++
3、采用管道-过滤器(Pipes and Filters)风格实现解释器
图2 管道-过滤器风格
图 3 编译器模型示意图
本实验,实现的是词法分析和语法分析两个部分。
四、实验步骤:
代码如下:
1 packagecom.brainstrong.uamis.util;2
3 importjava.io.InputStream;4 importjava.util.ArrayList;5 importjava.util.List;6 importjava.util.Scanner;7 importjava.util.StringTokenizer;8
9 /**
10 * JAVA实现四则运算解释器11 *12 *@author旭旭13 * @create 2017-10-27 19:4314 **/
15 public classCalc {16
17 public static voidmain(String[] args) {18 Scanner scanner = newScanner(System.in);19 String exp =scanner.nextLine();20 System.out.println(calc(exp));21 }22
23 /**
24 *25 *@paramexp 四则表达式26 *@return
27 */
28 public static doublecalc(String exp){29 //1.把表示负数的-号换成@号
30 exp =negativeToAtChar(exp);31 //2.数字的分类
32 List numbers =splitNumExp(exp);33 //3.运算符的分离
34 List ops =splitOpfromExp(exp);35 //4.先乘除
36 for (int i = 0; i < ops.size(); i++) {37 //判断,运算符是否是乘除
38 char op =ops.get(i);39 //是,取出,运算
40 if (op == ‘*‘ || op == ‘/‘) {41 //取出来,运算
42 ops.remove(i);//后面的数据往前顺序移动43 //运算44 //从数字容器中取出对应运算符的两个数字
45 double d1 =numbers.remove(i);46 double d2 =numbers.remove(i);47
48 if (op == ‘*‘) {49 d1 *=d2;50 }else{51 d1 /=d2;52 }53
54 //把运算结果放入数字容器中i的位置
55 numbers.add(i, d1);//原来i位置(包括)后面的数据依次往后顺移
56 i--;57 }58 }59 //5.后加减
60 while (!ops.isEmpty() ) {61 char op = ops.remove(0);62 double d1 = numbers.remove(0);63 double d2 = numbers.remove(0);64 //运算
65 if (op == ‘+‘) {66 d1 +=d2;67 } else{68 d1 -=d2;69 }70 //把运算结果插入到数字容器中0的位置
71 numbers.add(0, d1);72 }73 //6.容器中的第一个数据就是结果
74 return numbers.get(0);75 }76
77 /**
78 * 从表达式中分离表达式和运算符79 *@paramexp80 *@return
81 */
82 private static ListsplitOpfromExp(String exp) {83 List ops = new ArrayList();84 StringTokenizer st = new StringTokenizer(exp, "[email protected]");85 while(st.hasMoreTokens()) {86 char c = st.nextElement().toString().trim().charAt(0);87 ops.add(c);88 }89 returnops;90 }91
92 /**
93 * 分离出数字94 *@paramexp95 *@return
96 */
97 private static ListsplitNumExp(String exp) {98 List numbers = new ArrayList();99 StringTokenizer st = new StringTokenizer(exp, "+-*/");100 while(st.hasMoreTokens()) {101 String numStr =st.nextElement().toString().trim();102 if (numStr.charAt(0) == ‘@‘) {103 numStr = "-" + numStr.substring(1);104 }105 numbers.add(Double.parseDouble(numStr));106 }107 returnnumbers;108 }109
110 /**
111 * 把-号换成@号112 *@paramexp113 *@return
114 */
115 private staticString negativeToAtChar(String exp) {116 for (int i = 0; i < exp.length(); i++) {117 char c =exp.charAt(i);118 if (c == ‘-‘) {119 //判断是否是负数
120 if (i == 0) {121 //第一个位置肯定是负数
122 exp = "@"+exp.substring(1);123 }else{124 //不是第一个位置125 //判断前一个位置是否是运算符
126 char cprev = exp.charAt(i - 1);127 if (cprev == ‘+‘ || cprev == ‘-‘ || cprev == ‘*‘ || cprev == ‘/‘) {128 exp = exp.substring(0, i)+"@"+exp.substring(i+1);129 }130 }131 }132 }133 returnexp;134 }135
136 }