高级农民
- 积分
- 2724
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2017-6-18
- 最后登录
- 1970-1-1
|
本帖最后由 magicsets 于 2018-1-13 02:31 编辑
我把这个也写了下,但是代码量多了不少... 主要是110行到294行的语法树的处理方面,供参考~ (PS 感谢你的大米!不用再加了哈)
(不过目前这个代码不考虑运算符的交换性、结合性和分配性 -- 比如(1 + x - 2) * 3可以化简为x*3 - 3 -- 要支持这些的话要写一个rule-based system对语法树进行各种变换)- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Stack;
- import java.util.StringJoiner;
- public class Main {
- public static void main(String[] args) {
- // 一个使用样例
- Calculator calc = new Calculator();
- // 中间的数字是优先级(precedence),数字越小优先级越高
- // 这里限定二元运算符是left associative,一元运算符是right associative
- calc.registerOperation("+", 500, (a, b) -> a + b);
- calc.registerOperation("-", 500, (a, b) -> a - b);
- calc.registerOperation("*", 400, (a, b) -> a * b);
- calc.registerOperation("/", 400, (a, b) -> a / b);
- calc.registerOperation("^", 200, (a, b) -> (int) Math.pow(a, b));
- calc.registerOperation("-", 100, (a) -> -a);
- // 也可以支持函数,函数本质上是前缀表达式,就不需要优先级信息了
- calc.registerFunction("abs", (int ...a) -> Math.abs(a[0]));
- calc.registerFunction("min", (int ...a) -> Arrays.stream(a).min().getAsInt());
- calc.registerFunction("max", (int ...a) -> Arrays.stream(a).max().getAsInt());
- calc.setVariable("software", 3);
- String s1 = calc.evaluate("software * 2 + (1 - hardware) * (2 + 3) + min(a + 5, 3 * 8)");
- System.out.println("s1 = " + s1);
- // 输出:s1 = 6 + (1 - hardware) * 5 + min(a + 5, 24)
- calc.setVariable("hardware", 5);
- String s2 = calc.evaluate(s1);
- System.out.println("s2 = " + s2);
- // 输出:s2 = -14 + min(a + 5, 24)
- calc.setVariable("a", 10);
- String s3 = calc.evaluate(s2);
- System.out.println("s3 = " + s3);
- // 输出:s3 = 1
- }
- }
- class Calculator {
- private Map<String, OperationInfo<UnaryOperation>> unaryOperations;
- private Map<String, OperationInfo<BinaryOperation>> binaryOperations;
- private Map<String, Function> functions;
- private Map<String, Integer> environment;
- public Calculator() {
- this.unaryOperations =
- new HashMap<String, OperationInfo<UnaryOperation>>();
- this.binaryOperations =
- new HashMap<String, OperationInfo<BinaryOperation>>();
- this.functions = new HashMap<String, Function>();
- this.environment = new HashMap<String, Integer>();
- }
- // 注册一个一元运算符
- public void registerOperation(String operator, int precedence,
- UnaryOperation operation) {
- unaryOperations.put(
- operator, new OperationInfo<UnaryOperation>(precedence, operation));
- }
- // 注册一个二元运算符
- public void registerOperation(String operator, int precedence,
- BinaryOperation operation) {
- binaryOperations.put(
- operator, new OperationInfo<BinaryOperation>(precedence, operation));
- }
- // 注册一个函数
- public void registerFunction(String name, Function function) {
- functions.put(name, function);
- }
- // 设置变量的值
- public void setVariable(String name, int value) {
- environment.put(name, value);
- }
- // 调用Executor对表达式进行计算
- public String evaluate(String expression) {
- CalculatorExecutor executor =
- new CalculatorExecutor(unaryOperations, binaryOperations,
- functions, environment, expression);
- return executor.run().toString();
- }
- }
- // 对一元运算符的抽象
- interface UnaryOperation {
- public int apply(int operand);
- }
- // 对二元运算符的抽象
- interface BinaryOperation {
- public int apply(int lhs, int rhs);
- }
- // 对函数的抽象
- interface Function {
- public int apply(int ...operands);
- }
- // 语法树
- abstract class Expression {
- public abstract int getPrecedence();
- public abstract String toString();
- public abstract Expression eval(Map<String, Integer> environment);
- protected String addParenthese(String s, int innerPrecedence) {
- return innerPrecedence >= getPrecedence() ? "(" + s + ")" : s;
- }
- }
- // 语法树:一元表达式
- class UnaryExpression extends Expression {
- private final String operator;
- private final UnaryOperation operation;
- private final int precedence;
- private final Expression operand;
- public UnaryExpression(String operator, UnaryOperation operation,
- int precedence, Expression operand) {
- this.operator = operator;
- this.operation = operation;
- this.precedence = precedence;
- this.operand = operand;
- }
- @Override
- public Expression eval(Map<String, Integer> environment) {
- Expression result = operand.eval(environment);
- if (result instanceof Literal) {
- return new Literal(operation.apply(((Literal)result).value));
- }
- return new UnaryExpression(operator, operation, precedence, result);
- }
- @Override
- public int getPrecedence() {
- return precedence;
- }
- @Override
- public String toString() {
- return operator + addParenthese(operand.toString(), operand.getPrecedence());
- }
- }
- // 语法树:二元表达式
- class BinaryExpression extends Expression {
- private final String operator;
- private final BinaryOperation operation;
- private final int precedence;
- private final Expression lhsOperand;
- private final Expression rhsOperand;
- public BinaryExpression(String operator,
- BinaryOperation operation, int precedence,
- Expression lhsOperand, Expression rhsOperand) {
- this.operator = operator;
- this.operation = operation;
- this.precedence = precedence;
- this.lhsOperand = lhsOperand;
- this.rhsOperand = rhsOperand;
- }
- @Override
- public Expression eval(Map<String, Integer> environment) {
- Expression lhsResult = lhsOperand.eval(environment);
- Expression rhsResult = rhsOperand.eval(environment);
- if (lhsResult instanceof Literal && rhsResult instanceof Literal) {
- return new Literal(
- operation.apply(((Literal)lhsResult).value, ((Literal)rhsResult).value));
- }
- return new BinaryExpression(operator, operation, precedence, lhsResult, rhsResult);
- }
- @Override
- public int getPrecedence() {
- return precedence;
- }
- @Override
- public String toString() {
- return addParenthese(lhsOperand.toString(), lhsOperand.getPrecedence() - 1) +
- " " + operator + " " +
- addParenthese(rhsOperand.toString(), rhsOperand.getPrecedence());
- }
- }
- // 语法树:函数调用
- class FunctionCall extends Expression {
- private final String functor;
- private final Function function;
- private final Expression[] arguments;
- public FunctionCall(String functor,
- Function function,
- Expression[] arguments) {
- this.functor = functor;
- this.function = function;
- this.arguments = arguments;
- }
- @Override
- public Expression eval(Map<String, Integer> environment) {
- Expression[] results = new Expression[arguments.length];
- for (int i = 0; i < arguments.length; ++i) {
- results[i] = arguments[i].eval(environment);
- }
- boolean allLiterals =
- Arrays.stream(results).allMatch(arg -> arg instanceof Literal);
- if (allLiterals) {
- int[] literals = new int[arguments.length];
- for (int i = 0; i < arguments.length; ++i) {
- literals[i] = ((Literal)results[i]).value;
- }
- return new Literal(function.apply(literals));
- }
- return new FunctionCall(functor, function, results);
- }
- @Override
- public int getPrecedence() {
- return 0;
- }
- @Override
- public String toString() {
- StringJoiner argJoiner = new StringJoiner(", ");
- for (Expression arg : arguments) {
- argJoiner.add(arg.toString());
- }
- return functor + "(" + argJoiner.toString() + ")";
- }
- }
- // 语法树:常量值
- class Literal extends Expression {
- public final int value;
- public Literal(int value) {
- this.value = value;
- }
- @Override
- public Expression eval(Map<String, Integer> environment) {
- return this;
- }
- @Override
- public int getPrecedence() {
- return 0;
- }
- @Override
- public String toString() {
- return String.valueOf(value);
- }
- }
- // 语法树:变量
- class Variable extends Expression {
- private final String name;
- public Variable(String name) {
- this.name = name;
- }
- @Override
- public Expression eval(Map<String, Integer> environment) {
- Integer value = environment.get(name);
- return value == null ? this : new Literal(value);
- }
- @Override
- public int getPrecedence() {
- return 0;
- }
- @Override
- public String toString() {
- return name;
- }
- }
- // 用于打包operation和对应的precedence信息的小类
- class OperationInfo<T> {
- public final int precedence;
- public final T operation;
- public OperationInfo(int precedence, T operation) {
- this.precedence = precedence;
- this.operation = operation;
- }
- }
- // LL(1) Recursive Descent Syntax Directed Translator
- class CalculatorExecutor {
- private final Map<String, OperationInfo<UnaryOperation>> unaryOperations;
- private final Map<String, OperationInfo<BinaryOperation>> binaryOperations;
- private final Map<String, Function> functions;
- private Map<String, Integer> environment;
- private final String stream;
- private int position;
- // 词法部分也合并到这个类里了
- private enum TokenType {
- INTEGER,
- NAME,
- OPERATOR,
- LPAREN,
- RPAREN,
- COMMA,
- EOS,
- ERROR
- }
- private class Token {
- public final TokenType type;
- public final Object payload;
- public final int columnNumber;
- public Token(TokenType type, int columnNumber) {
- this(type, columnNumber, null);
- }
- public Token(TokenType type, int columnNumber, Object payload) {
- this.type = type;
- this.payload = payload;
- this.columnNumber = columnNumber;
- }
- }
- private Stack<Token> tokens;
- public CalculatorExecutor(
- Map<String, OperationInfo<UnaryOperation>> unaryOperations,
- Map<String, OperationInfo<BinaryOperation>> binaryOperations,
- Map<String, Function> functions,
- Map<String, Integer> environment,
- String stream) {
- this.unaryOperations = unaryOperations;
- this.binaryOperations = binaryOperations;
- this.functions = functions;
- this.environment = environment;
- this.stream = stream;
- this.position = 0;
- this.tokens = new Stack<Token>();
- }
- public Expression run() {
- Expression expr = parseExpr(Integer.MAX_VALUE);
- passNextToken(TokenType.EOS);
- return expr.eval(environment);
- }
- //////////////////////////////////////////////////////////////////////////////
- // 语法处理部分
- private Expression parseExpr(int precedence) {
- Expression expr = parseFactor(precedence);
- // 二元运算符,注意这里对优先级的处理方法
- while (hasNextToken(TokenType.OPERATOR)) {
- Token token = nextToken();
- String operator = (String)token.payload;
- OperationInfo<BinaryOperation> info = binaryOperations.get(operator);
- if (info == null || info.precedence >= precedence) {
- pushBack(token);
- break;
- }
- expr = new BinaryExpression(operator, info.operation, info.precedence,
- expr, parseExpr(info.precedence));
- }
- return expr;
- }
- private Expression parseFactor(int precedence) {
- Token token = nextToken();
- // Case 1. 数字自身
- if (token.type == TokenType.INTEGER) {
- return new Literal((Integer)token.payload);
- }
- // Case 2. 一元运算符
- if (token.type == TokenType.OPERATOR) {
- String operator = (String)token.payload;
- OperationInfo<UnaryOperation> info = unaryOperations.get(operator);
- if (info == null || info.precedence > precedence) {
- error(token);
- }
- return new UnaryExpression(operator, info.operation,
- info.precedence, parseExpr(info.precedence));
- }
- // Case 3. 函数调用或者变量
- if (token.type == TokenType.NAME) {
- if (hasNextToken(TokenType.LPAREN)) {
- String functor = (String)token.payload;
- Function function = functions.get(functor);
- if (function == null) {
- error(token);
- }
- ArrayList<Expression> args = new ArrayList<Expression>();
- passNextToken(TokenType.LPAREN);
- while (!hasNextToken(TokenType.RPAREN)) {
- args.add(parseExpr(Integer.MAX_VALUE));
- if (!hasNextToken(TokenType.COMMA)) {
- break;
- }
- nextToken();
- }
- passNextToken(TokenType.RPAREN);
- return new FunctionCall(
- functor, function, args.toArray(new Expression[args.size()]));
- } else {
- return new Variable((String)token.payload);
- }
- }
- // Case 4. 括号表达式
- if (token.type == TokenType.LPAREN) {
- Expression expr = parseExpr(Integer.MAX_VALUE);
- Token rp = nextToken();
- if (rp.type != TokenType.RPAREN) {
- error(token);
- }
- return expr;
- }
- error(token);
- return null;
- }
- //////////////////////////////////////////////////////////////////////////////
- // 词法处理部分
- private boolean hasNextToken(TokenType ...expected) {
- Token token = nextToken();
- boolean status = Arrays.stream(expected).anyMatch(x -> x == token.type);
- pushBack(token);
- return status;
- }
- private void passNextToken(TokenType ...expected) {
- Token token = nextToken();
- if (!Arrays.stream(expected).anyMatch(x -> x == token.type)) {
- error(token);
- }
- }
- private void pushBack(Token token) {
- tokens.add(token);
- }
- private Token nextToken() {
- if (!tokens.isEmpty()) {
- return tokens.pop();
- }
- while (position < stream.length() &&
- Character.isWhitespace(stream.charAt(position))) {
- ++position;
- }
- if (position >= stream.length()) {
- return new Token(TokenType.EOS, position);
- }
- final int start = position;
- final char ch = stream.charAt(position++);
- switch (ch) {
- case '(': return new Token(TokenType.LPAREN, start);
- case ')': return new Token(TokenType.RPAREN, start);
- case ',': return new Token(TokenType.COMMA, start);
- default: --position; break;
- }
- if (Character.isDigit(ch)) {
- return nextNumber();
- }
- if (Character.isAlphabetic(ch)) {
- return nextName();
- }
- return nextOperator();
- }
- private Token nextNumber() {
- final int start = position;
- while (position < stream.length() &&
- Character.isDigit(stream.charAt(position))) {
- ++position;
- }
- return new Token(TokenType.INTEGER, start,
- Integer.parseInt(stream.substring(start, position)));
- }
- private Token nextName() {
- final int start = position;
- while (position < stream.length() &&
- Character.isAlphabetic(stream.charAt(position))) {
- ++position;
- }
- return new Token(TokenType.NAME, start,
- stream.substring(start, position));
- }
- private Token nextOperator() {
- final int start = position;
- while (position < stream.length()) {
- final char ch = stream.charAt(position);
- if (Character.isWhitespace(ch) ||
- Character.isDigit(ch) ||
- Character.isAlphabetic(ch) ||
- ch == '(' || ch == ')' || ch == ',') {
- break;
- }
- ++position;
- }
- return new Token(TokenType.OPERATOR, start,
- stream.substring(start, position));
- }
- private void error(Token token) {
- throw new RuntimeException(
- "Syntax error: unexpected token at column " +
- (token.columnNumber+1) + " -- " + token.type.name() +
- (token.payload == null ? "" : " (" + token.payload.toString() + ")"));
- }
- }
复制代码 |
|