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


     parse_expression,parse_term,parse_primary_exp三函数间的递归调用是核心所在.

    标记类:

    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;
        }
    }

    分词器类:

    package com.heyang;
    
    import java.util.ArrayList;
    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=='+'){
                    addDigital2Tokens(swallowed);
                    swallowed="";
                    tokens.add(new Token(c,Token.TYPE_PLUS));
                }else if(c=='-'){
                    addDigital2Tokens(swallowed);
                    swallowed="";
                    tokens.add(new Token(c,Token.TYPE_MINUS));
                }else if(c=='*'){
                    addDigital2Tokens(swallowed);
                    swallowed="";
                    tokens.add(new Token(c,Token.TYPE_MULTI));
                }else if(c=='/'){
                    addDigital2Tokens(swallowed);
                    swallowed="";
                    tokens.add(new Token(c,Token.TYPE_DIVIDE));
                }else if(c=='('){
                    addDigital2Tokens(swallowed);
                    swallowed="";
                    tokens.add(new Token(c,Token.TYPE_LEFT_PAREN));
                }else if(c==')'){
                    addDigital2Tokens(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 addDigital2Tokens(String text) throws AnalyzerExp{
            if(text.trim().length()>0) {
                tokens.add(new Token(text,Token.TYPE_DIGITAL));
            }
        }
        
        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 index;
        
        public Evaluator(List<Token> tokens) {
            this.tokens=tokens;
            index=0;
        }
        
        public double evaluate() throws AnalyzerExp{
            return parse_expression();
        }
        
        private double parse_expression() throws AnalyzerExp{
            double left,right;
            Token currentToken;
            
            left=parse_term();
            for(;;) {
                if(index==tokens.size()) {
                    return left;
                }else {
                    currentToken=tokens.get(index);
                    index++;
                }
                
                if(currentToken.getType()!=Token.TYPE_PLUS && currentToken.getType()!=Token.TYPE_MINUS) {
                    index--;
                    break;
                }
                
                right=parse_term();
                
                if(currentToken.getType()==Token.TYPE_PLUS) {
                    left+= right;
                }else if(currentToken.getType()==Token.TYPE_MINUS) {
                    left-= right;
                }else {
                    index--;
                }
            }
            
            return left;
        }
        
        private double parse_term() throws AnalyzerExp{
            double left,right;
            Token currentToken;
            
            left=parse_primary_exp();
            for(;;) {
                if(index==tokens.size()) {
                    return left;
                }else {
                    currentToken=tokens.get(index);
                    index++;
                }
                
                if(currentToken.getType()!=Token.TYPE_MULTI && currentToken.getType()!=Token.TYPE_DIVIDE) {
                    index--;
                    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;
    
            if(index==tokens.size()) {
                return retval;
            }else {
                token=tokens.get(index);
                index++;
            }
            
            if(token.getType()==Token.TYPE_DIGITAL) {
                retval= token.getValue();
                return retval;
            }else if(token.getType()==Token.TYPE_LEFT_PAREN){
                retval=parse_expression();
                
                if(index==tokens.size()) {
                    return retval;
                }else {
                    token=tokens.get(index);
                    index++;
                }
                
                if(token.getType()!=Token.TYPE_RIGHT_PAREN) {
                    throw new AnalyzerExp("missing )");
                }
                
                return retval;
            }else {
                throw new AnalyzerExp(token+" should be a digital.");
            }
        }
        
        public static void main(String[] args) throws Exception{
            String exp="1+(2*3-4)*5-6";
            System.out.println("exp="+exp);
            Lexer lexer=new Lexer(exp);
            Evaluator e=new Evaluator(lexer.getTokens());
            System.out.println(e.evaluate());
        }
    }

    代码下载:

     https://files.cnblogs.com/files/heyang78/mathexpAnalyzer20200522-1.zip

    参考资料:

    前桥和弥著<自制编程语言>

    --2020年5月22日-

  • 相关阅读:
    耐性4/21
    吃枸杞上火4/11
    metro style app 的程序构成 以c# 为例 GIS
    ListView 和 GridView ————转 GIS
    最大程度地利用像素,适应视图状态的变更___转 GIS
    metro style 里面的控件一览 以 Windows.UI.Xaml.Controls空间 GIS
    Windows 8里的标准化输入 GIS
    漫游应用程序数据 GIS
    FlipView 知识准备 GIS
    Data Binding Notifications绑定通知 GIS
  • 原文地址:https://www.cnblogs.com/heyang78/p/12936911.html
Copyright © 2020-2023  润新知