递归向下解析算术表达式(二)

本文代码下载:https://files.cnblogs.com/files/heyang78/MathAnalyzer2-20200523-1.zip

新版代码出炉了:

Token类:

package com.heyang;

public class Token {
    public static final int TYPE_PLUS=1;
    public static final int TYPE_MINUS=2;
    public static final int TYPE_MULTI=3;
    public static final int TYPE_DIVIDE=4;
    
    public static final int TYPE_LEFT_PAREN=5;
    public static final int TYPE_RIGHT_PAREN=6;
    
    public static final int TYPE_DIGITAL=7;
    
    private int type;
    private String text;
    private double value;
    
    public Token(String text,int type) throws AnalyzerExp{
        this.text=text;
        this.type=type;
        
        try {
            this.value=Double.parseDouble(this.text);
        }catch(NumberFormatException ex) {
            throw new AnalyzerExp(String.format("Can not convert text:%s to double.", this.text));
        }
    }
    
    public Token(char c,int type) {
        this.text=String.valueOf(c);
        this.type=type;
    }
    
    public String toString() {
        if(this.type<TYPE_DIGITAL) {
            return this.text;
        }else {
            return String.valueOf(this.value);
        }
    }

    public int getType() {
        return type;
    }

    public double getValue() {
        return value;
    }
    
    public String getText() {
        return text;
    }
    
    public String getTypeStr() {
        if(type==TYPE_PLUS) {
            return "+";
        }else if(type==TYPE_MINUS){
            return "-";
        }else if(type==TYPE_MULTI){
            return "*";
        }else if(type==TYPE_DIVIDE){
            return "/";
        }else if(type==TYPE_LEFT_PAREN){
            return "(";
        }else if(type==TYPE_RIGHT_PAREN){
            return ")";
        }else if(type==TYPE_DIGITAL){
            return String.valueOf(value);
        }else {
            return "Unknown";
        }
    }
}

分词器类:

package com.heyang;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Lexer {
    private List<Token> tokens;
    
    public Lexer(String mathExp) throws AnalyzerExp{
        String swallowed="";
        
        tokens=new ArrayList<Token>();
        for(int i=0;i<mathExp.length();i++){
            char c=mathExp.charAt(i);
            
            if(Character.isWhitespace(c)){
                swallowed="";
            }else if(c=='+'){
                addText2Tokens(swallowed);
                swallowed="";
                tokens.add(new Token(c,Token.TYPE_PLUS));
            }else if(c=='-'){
                addText2Tokens(swallowed);
                swallowed="";
                tokens.add(new Token(c,Token.TYPE_MINUS));
            }else if(c=='*'){
                addText2Tokens(swallowed);
                swallowed="";
                tokens.add(new Token(c,Token.TYPE_MULTI));
            }else if(c=='/'){
                addText2Tokens(swallowed);
                swallowed="";
                tokens.add(new Token(c,Token.TYPE_DIVIDE));
            }else if(c=='('){
                addText2Tokens(swallowed);
                swallowed="";
                tokens.add(new Token(c,Token.TYPE_LEFT_PAREN));
            }else if(c==')'){
                addText2Tokens(swallowed);
                swallowed="";
                tokens.add(new Token(c,Token.TYPE_RIGHT_PAREN));
            }else {
                swallowed+=c;
            }
        }
        
        if(swallowed.length()>0) {
            tokens.add(new Token(swallowed,Token.TYPE_DIGITAL));
        }
    }
    
    private void addText2Tokens(String text) throws AnalyzerExp{
        if(text.trim().length()>0) {
            tokens.add(new Token(text,Token.TYPE_DIGITAL));
        }
    }
    
    private static String createRepeatedStr(String seed, int n) {
        return String.join("", Collections.nCopies(n, seed));
    }
    
    public void printTokenList() {
        final String layout = "%-20s %-20s %-20s %-20s %s";
        StringBuilder sb = new StringBuilder();

        sb.append("Token list\n");
        sb.append(String.format(layout, "Index", "Type No","Text","Type Desc","\n"));
        final String continuousStar = createRepeatedStr("-", 84);
        sb.append(continuousStar + "\n");
        int index=0;
        for(Token token:tokens) {
            sb.append(String.format(layout, String.valueOf(index),String.valueOf(token.getType()), token.getText(),token.getTypeStr(),"\n"));
            index++;
        }
        
        System.out.println(sb.toString());
    }
    
    public List<Token> getTokens(){
        return tokens;
    }
    
    public static void main(String[] args) throws Exception{
        Lexer lexer=new Lexer("3+(2*5)");
        List<Token> tokens=lexer.getTokens();
        for(Token t:tokens) {
            System.out.print(t);
        }
    }
}

计算类:

package com.heyang;

import java.util.List;

public class Evaluator {
    private List<Token> tokens;
    private int tokenIdx;
    
    public Evaluator(List<Token> tokens) {
        this.tokens=tokens;
        this.tokenIdx=0;
    }
    
    public double getResult() throws AnalyzerExp{
        return parse_expression();
    }
    
    private double parse_expression() throws AnalyzerExp{
        double left,right;
        Token currentToken;
        
        left=parse_term();
        for(;;) {
            currentToken=fetchToken();
            if(currentToken==null) {
                return left;
            }
            
            if(currentToken.getType()!=Token.TYPE_PLUS && currentToken.getType()!=Token.TYPE_MINUS) {
                returnToken();
                break;
            }
            
            right=parse_term();
            
            if(currentToken.getType()==Token.TYPE_PLUS) {
                left+= right;
            }else if(currentToken.getType()==Token.TYPE_MINUS) {
                left-= right;
            }else {
                returnToken();
            }
        }
        
        return left;
    }
    
    private double parse_term() throws AnalyzerExp{
        double left,right;
        Token currentToken;
        
        left=parse_primary_exp();
        for(;;) {
            currentToken=fetchToken();
            if(currentToken==null) {
                return left;
            }
            
            if(currentToken.getType()!=Token.TYPE_MULTI && currentToken.getType()!=Token.TYPE_DIVIDE) {
                returnToken();
                break;
            }
            
            right=parse_primary_exp();
            
            if(currentToken.getType()==Token.TYPE_MULTI) {
                left*= right;
            }else if(currentToken.getType()==Token.TYPE_DIVIDE) {
                left/= right;
            }
        }
        
        return left;
    }
    
    private double parse_primary_exp() throws AnalyzerExp{
        Token token;
        double retval=0.0;
        
        token=fetchToken();
        if(token==null) {
            return 0;
        }
        
        if(token.getType()==Token.TYPE_DIGITAL) {
            retval= token.getValue();
            return retval;
        }else if(token.getType()==Token.TYPE_LEFT_PAREN){
            retval=parse_expression();
            
            token=fetchToken();
            if(token==null) {
                return retval;
            }
            
            if(token.getType()!=Token.TYPE_RIGHT_PAREN) {
                throw new AnalyzerExp("missing )");
            }
            
            return retval;
        }else {
            throw new AnalyzerExp(token+" should be a digital.");
        }
    }
    
    private Token fetchToken() {
        if(tokenIdx>=tokens.size()) {
            return null;
        }else {
            Token t=tokens.get(tokenIdx);
            tokenIdx++;
            return t;
        }        
    }
    
    private void returnToken() {
        if(tokenIdx>0) {
            tokenIdx--;
        }
    }
}

调用:

package com.heyang;

import com.heyang.util.BracketChecker;
import com.heyang.util.Renderer;

public class EntryPoint {
    public static void main(String[] args) throws Exception{
        final String mathExp="(8+9)*7-2*(4+5)";
        
        // brackets is balanced
        BracketChecker checker=new BracketChecker();
        boolean isBalanced=checker.isBalanced(mathExp);
        if(isBalanced==false) {
            System.out.println(Renderer.paintBrown(checker.getErrMsg()));
            return;
        }
        
        // Split expression into tokens
        Lexer lexer=new Lexer(mathExp);
        // lexer.printTokenList();
        
        // Evaluate
        Evaluator evlt=new Evaluator(lexer.getTokens());
        System.out.println(mathExp+"="+evlt.getResult());
        
        //
        TreeBuilder builder=new TreeBuilder(lexer.getTokens());
        Node root=builder.getRoot();
        TreeOperation.show(root); 
        //root=null;
    }
}

输出:

(8+9)*7-2*(4+5)=101.0
            -            
         /     \         
      *           *      
    /   \       /   \    
  +       7   2       +  
 / \                 / \ 
8   9               4   5

--2020年5月23日--

posted @ 2020-05-23 14:33  逆火狂飙  阅读(158)  评论(1编辑  收藏  举报
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东