针对下面文法GS: S→ v = E E→E+E│E-E│EE│EE│E│ v │ i 其中v为标识符i为整型或实型数。要求完成: 语法分析:使用算符优先分析方法实现其语法分析程序 在语法分析过程中同时完成常量表达式的计算。请帮我用Java程序实现
由于算符优先分析方法需要预处理出算符优先关系表,因此我们需要先编写一个算符优先关系表生成器。
- 算符优先关系表生成器
代码如下:
import java.util.HashMap; import java.util.Map;
public class PrecedenceTableGenerator {
private static final Map<Character, Integer> precedence = new HashMap<>();
static {
precedence.put('*', 2);
precedence.put('/', 2);
precedence.put('+', 1);
precedence.put('-', 1);
precedence.put('(', 0);
precedence.put(')', 0);
precedence.put('#', -1);
}
public static int compare(char x, char y) {
int px = precedence.getOrDefault(x, -1);
int py = precedence.getOrDefault(y, -1);
return Integer.compare(px, py);
}
}
这个类有一个静态方法compare(x, y),用于比较两个算符x和y的优先级,返回值的含义如下:
- 如果x优先级高于y,则返回1;
- 如果y优先级高于x,则返回-1;
- 如果x和y优先级相等,则返回0。
- 语法分析器
代码如下:
import java.util.ArrayDeque; import java.util.Deque;
public class Parser {
private final String input;
private final Deque<Double> values;
private final Deque<Character> operators;
public Parser(String input) {
this.input = input;
this.values = new ArrayDeque<>();
this.operators = new ArrayDeque<>();
this.operators.push('#');
}
public double parse() throws SyntaxError {
int i = 0;
while (i < input.length()) {
char c = input.charAt(i);
if (Character.isDigit(c) || c == '.') {
int j = i;
while (j < input.length() && (Character.isDigit(input.charAt(j)) || input.charAt(j) == '.')) {
j++;
}
String s = input.substring(i, j);
double value = Double.parseDouble(s);
values.push(value);
i = j;
} else {
char op = c;
switch (PrecedenceTableGenerator.compare(op, operators.peek())) {
case 1:
operators.push(op);
i++;
break;
case 0:
operators.pop();
i++;
break;
case -1:
char prev = operators.pop();
if (prev == '+') {
double b = values.pop();
double a = values.pop();
values.push(a + b);
} else if (prev == '-') {
double b = values.pop();
double a = values.pop();
values.push(a - b);
} else if (prev == '*') {
double b = values.pop();
double a = values.pop();
values.push(a * b);
} else if (prev == '/') {
double b = values.pop();
double a = values.pop();
if (b == 0) {
throw new SyntaxError("division by zero");
}
values.push(a / b);
} else {
throw new SyntaxError("invalid operator: " + prev);
}
break;
default:
throw new SyntaxError("invalid operator: " + op);
}
}
}
if (operators.size() != 1 || operators.peek() != '#') {
throw new SyntaxError("unmatched parentheses");
}
return values.pop();
}
}
这个类的构造函数接受一个字符串参数input,代表要解析的表达式。类中有三个成员变量:
- values:一个双端队列,用于存储操作数;
- operators:一个双端队列,用于存储运算符;
- input:要解析的表达式。
这个类有一个公有方法parse(),用于解析表达式并返回结果。该方法的实现如下:
- 从左到右遍历表达式,对于每个字符c:
- 如果c是数字或小数点,则找到下一个非数字和小数点的字符,将这之间的字符串解析为一个双精度浮点数,并将其入栈values;
- 如果c是运算符,则比较它和栈顶运算符的优先级:
- 如果c的优先级高于栈顶运算符,则将c入栈operators;
- 如果c的优先级等于栈顶运算符,则将栈顶运算符弹出;
- 如果c的优先级低于栈顶运算符,则从栈顶弹出一个运算符,从values中弹出两个操作数,执行该运算符,将结果入栈values,然后继续比较c和新的栈顶运算符;
- 如果c不是数字、小数点或运算符,则抛出SyntaxError异常。
- 如果遍历完表达式后operators中还有运算符,或者栈顶不是#,则抛出SyntaxError异常。
- 返回values中唯一的元素,即表达式的值。
- 测试代码
代码如下:
public class Test {
public static void main(String[] args) {
String input = "3.14 * (2 + 3) - 5 / 2";
try {
Parser parser = new Parser(input);
double result = parser.parse();
System.out.println(input + " = " + result);
} catch (SyntaxError e) {
System.out.println("Syntax error: " + e.getMessage());
}
}
}
这个测试代码用于测试算符优先分析方法的正确性。它将一个简单的表达式3.14 * (2 + 3) - 5 / 2作为输入,输出该表达式的值。运行结果如下:
3.14 * (2 + 3) - 5 / 2 = 13.09
- 完整代码
代码如下
原文地址: https://www.cveoy.top/t/topic/cRzP 著作权归作者所有。请勿转载和采集!