Java课程project(SMAC计算器)----基于JavaSE

Java课程project(SMAC计算器)----基于JavaSE

新开了一门外教课程,Object-oriented Programming(JAVA),本章记录结课project。
This project is about making a Simple MAth Calculator (SMAC in the sequel) with some interesting features.
Author: ArthurWang
Enviroment: Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-48-generic x86_64)、openjdk 11.0.9.1
IDE: VScode

Introduction of functionalities

  1. Evaluate mathematical expressions made from numbers, operators (addition, subtraction, unary minus, multiplication, division, power) and parenthesis.
  2. Managing the precision of decimal.
  3. Define and use variables in mathematical expression. (Eg. let x = 3; reset x …)
  4. Managing errors. (Include ErrorException, SyntaxErrorException, LexicalErrorException, TokenException)
  5. Keeping track of the last value. (Eg. last …)
  6. Storing variables. (Eg. save “myfile”; load “myfile”; save “just-z-file” z …)
  7. Logging a session. (Eg. log “mylog”; log end …)
  8. More mathematical functions. (sin, cos, tan, abs)

Some ideas of design

  1. Singleton design idea and Multiton design idea.
  2. Factory design idea and Proxy design idea.
  3. Client (which is Smac.java) use the Interface to get service.

File structure

project: package of source file.
logFile: log file of user set log.
varFile: variables file of user set variable.

在这里插入图片描述

出于考虑该文章只贴出部分代码,即只给出了处理问题的逻辑方法。自定义的Exception文件、实现接口的Evaluator文件、Token、Test文件均没有贴出。

package project;

public interface IEvaluator {

    // Creat Token with lexical analysis.
    public void createInputToken(String input) throws LexicalErrorException, TokenException;

    // Sysntax analysis
    public boolean syntaxAnalysis() throws ErrorException, SyntaxErrorException, LexicalErrorException, TokenException;

    // Creat Mathematical evaluator and calculate
    public void mathEvaluator() throws ErrorException, SyntaxErrorException, TokenException;

    // Get varFile path
    public void varFilePath(String path);

    // Println output
    public void println(String len);

    // Print output
    public void print(String len);

    // Log situtation
    public void logUserInput(String input);

    // Get varFile path
    public void logFilePath(String path);

    // Log session
    public boolean logSession();

}
package project;

import java.util.*;

/**
 * this class is to handle different keywords command.
 * the SyntaxAnalyzer just need to give the factory to process.
 */
public class KeywordsCommFactory {

    private static final KeywordsCommFactory command = new KeywordsCommFactory();

    private KeywordsCommFactory() {
    }

    public static KeywordsCommFactory getKeywordsCommFactory() {
        return command;
    }

    public void factory(Tokenizer myTokenizer, Map<String, Double> variables)throws TokenException, SyntaxErrorException, ErrorException, LexicalErrorException {

        Token t = myTokenizer.readNextToken();

        if (t.getIdentifier().equals("let")) {
            letCommand(myTokenizer, variables);
        } else if (t.getIdentifier().equals("setprecision")) {
            precCommand(myTokenizer);
        } else if (t.getIdentifier().equals("reset")) {
            resetCommand(myTokenizer, variables);
        } else if (t.getIdentifier().equals("last")) {
            lastCommand(myTokenizer);
        } else if (t.getIdentifier().equals("save")) {
            saveCommand(myTokenizer, variables);
        } else if (t.getIdentifier().equals("saved")) {
            savedCommand(myTokenizer);
        }else if (t.getIdentifier().equals("load")){
            loadCommand(myTokenizer, variables);
        }else if (t.getIdentifier().equals("log")){
            logCommand(myTokenizer);
        }else if (t.getIdentifier().equals("logged")){
            loggerCommand(myTokenizer);
        }
        /*
         * else if (t.getIdentifier().equals("define")){
         * }
         */
    }

    /**
     * Command Process.
     * Different keywords, Factory use different method
     */
    
    private void letCommand(Tokenizer myTokenizer, Map<String, Double> variables)throws SyntaxErrorException, TokenException {
        // only one "let" situtation
        if (!myTokenizer.hasNextToken()) {
            letCommandOutput(variables);
            return;
        }

        Token t = myTokenizer.readNextToken();
        if (!t.isIdentifier()) {
            throw new SyntaxErrorException("is not a vaild variable name");
        }
        String variable = t.getIdentifier();

        t = myTokenizer.readNextToken();
        if (!t.isEqual()) {
            throw new SyntaxErrorException("is not a vaild let command");
        }

        MathematicalEvaluator mathEvaluer = MathematicalEvaluator.getMathematicalEvaluator();
        Double value = mathEvaluer.calculate(myTokenizer, variables);
        if (value == null) {
            throw new SyntaxErrorException("is not a vaild let command");
        }
        variables.put(variable, value);
        ResOutput.getResOutput().println(value);
    }

    private void letCommandOutput(Map<String, Double> variables) {
        Iterator<String> it = variables.keySet().iterator();
        if (!it.hasNext()) {
            ResOutput.getResOutput().println("no variable defined");
            return;
        }
        while (it.hasNext()) {
            String var = it.next();
            ResOutput.getResOutput().println(var + " = " + variables.get(var));
        }
    }

    private void precCommand(Tokenizer myTokenizer) throws SyntaxErrorException, TokenException {
        // only one "setprecision" situtation
        if (!myTokenizer.hasNextToken()) {
            int precision = ResOutput.getResOutput().getPrecision();
            if (precision == -1) {
                ResOutput.getResOutput().println("current precision is default. You can set a precision");
            } else {
                ResOutput.getResOutput().println("current precision is " + precision);
            }
            return;
        }
        // if token is not a number or if myTokenizer has next token after the precision
        // value. Is worng.
        Token t = myTokenizer.readNextToken();
        if (!t.isNumber() || myTokenizer.hasNextToken()) {
            throw new SyntaxErrorException("is not a vaild precision");
        }

        // set the precision
        String temp = String.valueOf(t.getNumber());
        String res = temp.substring(0, temp.indexOf("."));
        int prec = Integer.parseInt(res);
        ResOutput.getResOutput().setPrecision(prec);
        ResOutput.getResOutput().println("current precision is " + ResOutput.getResOutput().getPrecision());
    }

    private void resetCommand(Tokenizer myTokenizer, Map<String, Double> variables)
            throws SyntaxErrorException, TokenException {
        // only one "reset" situtation.
        if (!myTokenizer.hasNextToken()) {
            resetCommandOutput(variables);
            return;
        }

        while (myTokenizer.hasNextToken()) {
            Token t = myTokenizer.readNextToken();
            if (!t.isIdentifier()) {
                throw new SyntaxErrorException("is not a vaild variable name");
            }
            String variable = t.getIdentifier();
            if (variables.containsKey(variable)) {
                variables.remove(variable);
                ResOutput.getResOutput().println(variable + " has been reset");
            } else {
                ResOutput.getResOutput().println(variable + " not defined");
            }
        }
    }

    private void resetCommandOutput(Map<String, Double> variables) {
        Iterator<String> it = variables.keySet().iterator();
        if (!it.hasNext()) {
            ResOutput.getResOutput().println("no variable defined");
            return;
        }
        while (it.hasNext()) {
            String var = it.next();
            ResOutput.getResOutput().println(var + " has been reset");
        }
        variables.clear();
    }

    private void lastCommand(Tokenizer myTokenizer) throws SyntaxErrorException {
        if (myTokenizer.hasNextToken()) {
            throw new SyntaxErrorException("is not a vaild last command");
        }
        if (LastCaluNum.getLastCaluNum().getNum() == null) {
            ResOutput.getResOutput().println("no calculate resulet");
            return;
        }
        ResOutput.getResOutput().println(LastCaluNum.getLastCaluNum().getNum());
    }

    private void saveCommand(Tokenizer myTokenizer, Map<String, Double> variables) throws SyntaxErrorException, TokenException{
        // only one "save" situtation
        if (!myTokenizer.hasNextToken()) { throw new SyntaxErrorException("is not a vaild save command. Maybe try saved? "); }

        Token t = myTokenizer.readNextToken();
        if (!t.isString()){  throw new SyntaxErrorException("is not a vaild save command"); }
        String variable = t.getString();
        String file = variable.substring(1,variable.length()-1);

        if (myTokenizer.hasNextToken()){
            Token var = myTokenizer.readNextToken();
            if (var.isIdentifier()){
                StorVar.getStorVar().saveFileOneLetter(file, variables, var.getIdentifier());
            } else{
                throw new SyntaxErrorException("is not a vaild save command");
            }
        } else{
            StorVar.getStorVar().saveFile(file, variables);
        }
        if (myTokenizer.hasNextToken()) { throw new SyntaxErrorException("is not a vaild save command. You only can chose one variable."); }
    }

    private void savedCommand(Tokenizer myTokenizer) throws SyntaxErrorException{
        if (myTokenizer.hasNextToken()) { throw new SyntaxErrorException("is not a vaild saved command"); }
        StorVar.getStorVar().savedFile();
    }

    private void loadCommand(Tokenizer myTokenizer, Map<String, Double> variables) throws SyntaxErrorException, TokenException, ErrorException, LexicalErrorException {
        // only one "load" situtation
        if (!myTokenizer.hasNextToken()) { throw new SyntaxErrorException("is not a vaild load command. Please input the load file"); }

        Token t = myTokenizer.readNextToken();
        if (!t.isString()) { throw new SyntaxErrorException("is not a vaild load file."); }
        String file = t.getString().substring(1,t.getString().length()-1);
        ArrayList<String> res = StorVar.getStorVar().loadVar(file);
        for (int i = 0; i < res.size(); i++){
            myTokenizer = new Tokenizer(res.get(i));
            myTokenizer.readNextToken();
            letCommand(myTokenizer, variables);
        }
    }

    private void logCommand(Tokenizer myTokenizer) throws SyntaxErrorException, TokenException {
        // only "log" situtation
        if (!myTokenizer.hasNextToken()) { 
            if (LogSe.getLoger().getLogActiveButton()) { 
                ResOutput.getResOutput().println(LogSe.getLoger().getFile());
            }else {
                ResOutput.getResOutput().println("not in Logging session");
            }
            return;
        }

        Token t = myTokenizer.readNextToken();
        if (!t.isString()) {
            if (LogSe.getLoger().getLogActiveButton() && t.isIdentifier() && t.getIdentifier().equals("end")){
                ResOutput.getResOutput().println("session was logged to "+LogSe.getLoger().getFile());
                LogSe.getLoger().quitLoger();
                return;
            }else{
                throw new SyntaxErrorException("is not a vaild log command."); 
            }
        }

        if (myTokenizer.hasNextToken()) { throw new SyntaxErrorException("is not a vaild log command.");  }

        String file = t.getString().substring(1,t.getString().length()-1);
        LogSe.getLoger().setFile(file);
        ResOutput.getResOutput().println("logging session to "+file);
        LogSe.getLoger().activeLoger();
    }

    private void loggerCommand(Tokenizer myTokenizer) throws SyntaxErrorException {
        if (myTokenizer.hasNextToken()) { throw new SyntaxErrorException("is not a vaild logged command."); }
        Set<String> temp = LogSe.getLoger().getFileSet();
        temp.forEach( (str)->ResOutput.getResOutput().println(str) );
    }
}

package project;

/**
 * last value trace class.
 * Because many class need to use last value, and reference transmit cause the reduency
 * so use this class to keep the last value.
 */
public class LastCaluNum{

    private Double num;

    private static final LastCaluNum last = new LastCaluNum();

    private LastCaluNum(){}

    public static LastCaluNum getLastCaluNum(){
        return last;
    }

    public void setNum(Double num){
        this.num = num;
    }
    public Double getNum(){
        return this.num;
    }

}
package project;

import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
 * this class for log situtation.
 */
public class LogSe {

    private boolean logSesActiveButton;
    private String path;
    private Set<String> fileName;
    private String currentFile;

    public static final LogSe myLoger = new LogSe();

    private LogSe() {
        this.logSesActiveButton = false;
        this.path = "./"; // default situation to save logFile in project path.
        fileName = new HashSet<>();
    }

    public static LogSe getLoger(){
        return myLoger;
    }
    
    public void activeLoger() {
        this.logSesActiveButton = true;
    }

    public boolean getLogActiveButton() {
        return this.logSesActiveButton;
    }

    public void quitLoger(){
        this.logSesActiveButton = false;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getPath() {
        return this.path;
    }

    public void setFile(String file){
        this.currentFile = file;
        if (!fileName.contains(currentFile)) { fileName.add(file); }
    }

    public String getFile(){
        return this.currentFile;
    }

    public Set<String> getFileSet(){
        return fileName;
    }

    public void writeLogFile(String input, boolean changeLenOrnNot) {
        
        try {
            FileWriter myFileWriter = new FileWriter(this.path + "/" + currentFile, true);
            write2File(myFileWriter, input, changeLenOrnNot);
            myFileWriter.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void write2File(FileWriter myFileWriter, String text, boolean changeLenOrnNot) throws IOException {
        myFileWriter.write(text);
        if (changeLenOrnNot) { myFileWriter.write("\n"); }
    }
}
package project;
import java.util.*;

public class MathematicalEvaluator{
    
    private Stack<Double> valueStack;
    private Stack<thisOp> operatorStack;

    private static final MathematicalEvaluator mathEvaluer = new MathematicalEvaluator();

    private MathematicalEvaluator(){
        valueStack = new Stack<>();
        operatorStack = new Stack<>();
    }

    public static MathematicalEvaluator getMathematicalEvaluator(){
        return mathEvaluer;
    }

    public Double calculate(Tokenizer tokenier, Map<String, Double> variables)throws TokenException, SyntaxErrorException{
        try{
            // init the stack
            if (!valueStack.isEmpty()) { valueStack.clear(); }
            if (!operatorStack.isEmpty()) { operatorStack.clear(); }

            while (tokenier.hasNextToken()){
                Token t = tokenier.readNextToken();
                
                if (t.isNumber()){
                    valueStack.push(t.getNumber());
                }else if (t.isIdentifier()){
                    idenProcess(t, variables);
                }else if (t.isOperator()){
                    operaProcess(t);
                }else if (t.isDelimiter()){
                    parenProces(t);
                }
            }

            while (!operatorStack.isEmpty()){
                loadNumCalu();
            }
        }catch(Exception e){
            throw new SyntaxErrorException("malformed expression");
        }

        if (!operatorStack.isEmpty() || valueStack.size() != 1){ throw new SyntaxErrorException("malformed expression"); }
        
        Double res = valueStack.pop();
        LastCaluNum.getLastCaluNum().setNum(res);
        return res;
    }

    private void idenProcess(Token t, Map<String, Double> variables) throws TokenException{
        if (moreMathFunAdd(t.getIdentifier())){
            operaIdenProcess(t);
        }else{
            if (t.getIdentifier().equals("last")){
                Double value = LastCaluNum.getLastCaluNum().getNum();
                valueStack.push(value);
            }else{
                Double value = variables.get(t.getIdentifier());
                valueStack.push(value);
            }
        }
    }
    
    private void operaIdenProcess(Token t) throws TokenException {
        thisOp op = new thisOp(t.getIdentifier());
        while (!operatorStack.isEmpty() && operatorStack.peek().getPriority() >= op.getPriority()){
            loadNumCalu();
        }
        operatorStack.push(op);
    }

    // add the more math fun.
    private boolean moreMathFunAdd(String operator){
        return operator.equals("cos")||operator.equals("sin")||operator.equals("tan")||operator.equals("abs");
    }

    private void parenProces(Token t) throws TokenException {
        if (t.getDelimiter().equals("(")){
            thisOp op = new thisOp("(");
            operatorStack.push(op);
        }else if (t.getDelimiter().equals(")")){
            while (!operatorStack.peek().getName().equals("(")){
                loadNumCalu();
            }
            operatorStack.pop();
        }
    }


    private void operaProcess(Token t) throws TokenException {
        thisOp op = new thisOp(t.getOperator());
        while (!operatorStack.isEmpty() && operatorStack.peek().getPriority() >= op.getPriority()){
            loadNumCalu();
        }
        operatorStack.push(op);
    }

    private void loadNumCalu() throws TokenException {
        
        thisOp op = operatorStack.pop();
        
        if (op.getArity() == 2){
            Double y = valueStack.pop();
            Double x = valueStack.pop();

            if (op.getName().equals("+")){
                add(x,y);
            }else if (op.getName().equals("-")){
                sub(x,y);
            }else if (op.getName().equals("*")){
                mul(x,y);
            }else if (op.getName().equals("/")){
                div(x,y);
            }else if (op.getName().equals("^")){
                exp(x,y);
            }

        }else if (op.getArity() == 1){
            Double x = valueStack.pop();

            if (op.getName().equals("~")){
                rev(x);
            }else if (op.getName().equals("cos")){
                cos(x);
            }else if (op.getName().equals("sin")){
                sin(x);
            }else if (op.getName().equals("tan")){
                tan(x);
            }else if (op.getName().equals("abs")){
                abs(x);
            }
        }
    }

    private void add(Double x, Double y){
        valueStack.push(x+y);
    }
    private void sub(Double x, Double y){
        valueStack.push(x-y);
    }
    private void mul(Double x, Double y){
        valueStack.push(x*y);
    }
    private void div(Double x, Double y){
        valueStack.push(x/y);
    }
    private void exp(Double x, Double y){
        valueStack.push(Math.pow(x, y));
    }
    private void rev(Double x){
        valueStack.push(-x);
    }
    private void cos(Double x){
        valueStack.push(Math.cos(x));
    }
    private void sin(Double x){
        valueStack.push(Math.sin(x));
    }
    private void tan(Double x){
        valueStack.push(Math.tan(x));
    }
    private void abs(Double x){
        valueStack.push(Math.abs(x));
    }

}
package project;

public class ResOutput{

    private int precision;

    private static final ResOutput outputer = new ResOutput();

    private ResOutput(){
        this.precision = -1; // Default precision. just Output.
    }

    public static ResOutput getResOutput(){
        return outputer;
    }

    public void setPrecision(int precision){
        this.precision = precision;
    }

    public int getPrecision(){
        return this.precision;
    }

    public void println(Double num){
        // user not set the precision. Just ouput the num
        if (this.precision == -1){
            String checkInt = String.valueOf(num);
            if (checkInt.indexOf('.') == checkInt.length() - 2 && checkInt.charAt(checkInt.length()-1) == '0'){
                myPrintln(checkInt.substring(0, checkInt.length() - 2));
                return;
            }
            myPrintln(checkInt);
        }else{
            String temp = String.valueOf(num);
            int index = temp.indexOf(".");
            if (this.precision == 0){
                // lose the decimal of num.
                String res = temp.substring(0, index);
                myPrintln(res);
            }else{
                if (index+1+this.precision >= temp.length()){
                    myPrintln(temp);
                }else{
                    String res = temp.substring(0, index+1+this.precision);
                    myPrintln(res);
                }
            }
        }
    }

    private void myPrintln(String res){
        if (LogSe.getLoger().getLogActiveButton()) {
            LogSe.getLoger().writeLogFile(res, true);
        }
        System.out.println(res);
    }

    // overload
    public void println(String len){
        if (LogSe.getLoger().getLogActiveButton()) {
            LogSe.getLoger().writeLogFile(len, true);
        }
        System.out.println(len);
    }

    public void print(String len){
        if (LogSe.getLoger().getLogActiveButton()) {
            LogSe.getLoger().writeLogFile(len, false);
        }
        System.out.print(len);
    }

}


package project;

import java.util.*;

public class Smac{
    // path can be changed by client user
    public static final String VARPATH = "./varFile";
    public static final String LOGPATH = "./logFile";
    public static void main(String[] args) {
        Scanner console = new Scanner(System.in);

        // creat SMAC
        IEvaluator smac = new Evaluator();

        smac.println("Welcome to SMAC");
        smac.print("> ");
		String input = console.nextLine().trim();

        smac.varFilePath(VARPATH);
        smac.logFilePath(LOGPATH);
        
        while (!input.equals("exit")) {

            try{
                smac.createInputToken(input);
                if (!smac.syntaxAnalysis()){
                    smac.mathEvaluator();
                }
    
            }catch(Exception e){
                smac.println(e.toString());
                // use for debug
                // e.printStackTrace();
            }

            if(smac.logSession()){
                smac.print(">> ");
                input = console.nextLine();
                smac.logUserInput(input);
            }else{
                smac.print("> ");
                input = console.nextLine();
            }
        }

		console.close();
        smac.println("Thank you for using SMAC");
    }
}
package project;

import java.util.*;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.FileReader;
import java.io.IOException;

/**
 * this class use IO to save variables and load(get saved) variables.
 */

public class StorVar {
    
    private static StorVar myStorer;
    private String path;
    private ArrayList<String> fileName;
   
    private StorVar(){ fileName = new ArrayList<>(); }

    public static StorVar getStorVar(){
        if (myStorer == null){
            myStorer = new StorVar();
        }
        return myStorer;
    }

    public void loadPath(String p){
        this.path = p;
    }

    public void saveFile(String file, Map<String, Double> variables){
        if (!fileName.contains(file)){ fileName.add(file); }
        if (variables.isEmpty()) { ResOutput.getResOutput().println("no variables to save"); return; }

        try{
            FileWriter myFileWriter = new FileWriter(this.path+"/"+file);
            writeVar2File(myFileWriter, variables);
            myFileWriter.close();
            ResOutput.getResOutput().println("variables saved in "+file);

        }catch (IOException e){
            e.toString();
        }
        
    }

    private void writeVar2File(FileWriter myFileWriter, Map<String, Double> variables) throws IOException {
        Iterator<String> it = variables.keySet().iterator();
        while (it.hasNext()){
            String var = it.next();
            Double value = variables.get(var);
            myFileWriter.write("let "+var+" = "+value);
            myFileWriter.write("\n");
        }
    }

    public void saveFileOneLetter(String file, Map<String, Double> variables, String variable){
        if (!fileName.contains(file)){ fileName.add(file); }
        if (variables.isEmpty()) { ResOutput.getResOutput().println("no variables to save"); return;}
        if (!variables.containsKey(variable)) { ResOutput.getResOutput().println("variable is not defined"); return;}

        try{
            FileWriter myFileWriter = new FileWriter(this.path+"/"+file);
            writeVar2File(myFileWriter, variable, variables);
            myFileWriter.close();
            ResOutput.getResOutput().println("variables saved in "+file);
        }catch (IOException e){
            e.toString();
        }
    }
    // overload
    private void writeVar2File(FileWriter myFileWriter, String variable, Map<String, Double> variables) throws IOException {
        myFileWriter.write("let "+variable+" = "+variables.get(variable));
    }
    
    public void savedFile(){
        if (fileName.isEmpty()) { ResOutput.getResOutput().println("no file to save"); return; }
        for (String name : fileName) {
            ResOutput.getResOutput().println(name);
        }
    }

    public ArrayList<String> loadVar(String file) throws ErrorException {
        ArrayList<String> res = new ArrayList<>();
        
        try{
            BufferedReader myFileReader = new BufferedReader(new FileReader(this.path+"/"+file));
            readFile2Vars(myFileReader, res);
            myFileReader.close();
            ResOutput.getResOutput().println(file+" loaded");
        }catch (IOException e){
            throw new ErrorException("file is not exist");
        }
        return res;
    }

    private void readFile2Vars(BufferedReader myFileReader, ArrayList<String> res) throws IOException {
        String line;
        while ( (line = myFileReader.readLine()) != null) {
            res.add(line);
        }
    }
}


public class SyntaxAnalyzer{

    private static final SyntaxAnalyzer syntaxAnalyzer = new SyntaxAnalyzer();

    private SyntaxAnalyzer(){}
    
    public static SyntaxAnalyzer getSyntaxAnalyzer(){
        return syntaxAnalyzer;
    }

    public boolean analyse(Tokenizer myTokenizer, Set<String> keywords, Map<String, Double>variables)throws ErrorException, SyntaxErrorException, LexicalErrorException, TokenException {

        Token t = myTokenizer.peekNextToken();

        if (t.isNumber()) {
            return false;
        }else if (t.isDelimiter()){
            if (t.getDelimiter().equals("(")) { return false; }
        }else if (t.isIdentifier()){
            if (keywords.contains(t.getIdentifier())) {
                KeywordsCommFactory command = KeywordsCommFactory.getKeywordsCommFactory();
                command.factory(myTokenizer, variables);
                return true;
            }

            if (variables.containsKey(t.getIdentifier())) {
                return false;
            }else if (t.getIdentifier().equals("cos")||t.getIdentifier().equals("sin")||t.getIdentifier().equals("tan")||t.getIdentifier().equals("abs")){
                return false;
            }else {
                throw new ErrorException(t.getIdentifier() + " is not a variable");
            }

        }else {
            throw new SyntaxErrorException("not vaild input");
        }
        
        throw new SyntaxErrorException("not vaild input");
    }


}
package project;

public class thisOp{
    private String name;
    private int arity;
    private int priority;
    
    public thisOp(String name){
        this.name = name;
        this.arity = 0;
        this.priority = 0;
    }
    
    public String getName(){
        return this.name;
    }

    public int getArity() throws TokenException {
        switch(this.name){
            case"-":
                this.arity = 2;
                break;
            case"~":
                this.arity = 1;
                break;
            case"+":
                this.arity = 2;
                break;
            case"*":
                this.arity = 2;
                break;
            case"/":
                this.arity = 2;
                break;
            case"^":
                this.arity = 2;
                break;
            case"cos":
                this.arity = 1;
                break;
            case"sin":
                this.arity = 1;
                break;
            case"tan":
                this.arity = 1;
                break;
            case"abs":
                this.arity = 1;
                break;
            default:
                throw new TokenException("getArity worng");
        }
        return this.arity;
    }

    public int getPriority() throws TokenException {
        switch(this.name){
            case"-":
                this.priority = 1;
                break;
            case"~":
                this.priority = 2;
                break;
            case"+":
                this.priority = 1;
                break;
            case"*":
                this.priority = 2;
                break;
            case"/":
                this.priority = 2;
                break;
            case"^":
                this.priority = 3;
                break;
            case"(":
                this.priority = 0;
                break;
            case"cos":
                this.priority = 3;
                break;
            case"sin":
                this.priority = 3;
                break;
            case"tan":
                this.priority = 3;
                break;
            case"abs":
                this.priority = 3;
                break;
            default:
                throw new TokenException("getPriority worng");
        }
        return this.priority;
    }


}
package project;

import java.util.*;
import java.util.regex.Pattern;

public class Tokenizer {
	
	private Deque<Token> que;
	private static final char[] DELIMITER = {'=', '(', ')', ',', '^', '*', '/', '+', '-'};
	

	public Tokenizer(String input)throws LexicalErrorException, TokenException{
		que = new LinkedList<>();
		String[] temp = input.trim().split("[ \u0009]+");  // [/t] will split the 't', so replace to [\u0009]
		inputToToken(temp);
	}

	/**
	 * checks if there is more token to read
	 */
	public boolean hasNextToken() {
		return !que.isEmpty();
	}

	/**
	 * returns the next token to be read
	 * Throws a TokenException if there is
	 * no more token to peek in the Tokenizer
	 * YOU MAY ADD THROW CLAUSES TO THIS METHOD
	 */
	public Token peekNextToken() throws LexicalErrorException{
		if (!hasNextToken()) { throw new LexicalErrorException("no more token to peek"); }
		return que.peek();
	}

	/**
	 * reads and returns the next token to be read
	 * (i.e. the next token is removed from the tokenizer)
     * YOU MAY ADD THROW CLAUSES TO THIS METHOD
	 */
	public Token readNextToken() {
		return que.poll();
	}
	
	// add your private methods below

	private void inputToToken(String myString[]) throws LexicalErrorException, TokenException {
		ArrayList<String> delier = new ArrayList<>();

		// split by delimiter(except space and tab) every line.
		for (int i = 0; i < myString.length; i++){
			splitEveryLine(delier, myString[i]);
			buildTokenList(delier);
			delier.clear();
		}
	}

	// split by delimiter(except space and tab) every line.
	private void splitEveryLine(ArrayList<String> delier, String myString){
		// split the string by delimiter.
		String temp = "";
		for (int i = 0; i < myString.length(); i++){
			if (findDeliChar(myString.charAt(i))){
				if (!temp.isEmpty()) { delier.add(temp); }
				delier.add(String.valueOf(myString.charAt(i)));
				temp = "";
			} else{
				temp = temp + myString.charAt(i);
			}
		}
		if (!temp.isEmpty()) { delier.add(temp); }
	}

	// search delimiter.
	private boolean findDeliChar(char target){
		for (int i = 0; i < DELIMITER.length; i++){
			if (target == DELIMITER[i]){ return true; }
		}
		return false;
	}

	// build token list.
	private void buildTokenList(ArrayList<String> delier) throws LexicalErrorException, TokenException {
		for (int i = 0; i < delier.size(); i++){
			factoryToken(delier.get(i));
		}
	}

	// use factory idea.
	private void factoryToken(String str) throws LexicalErrorException, TokenException {
		
		switch (str){
			case "=" :
				que.add(Token.makeEQUAL());
				break;
			case "(" :
				que.add(Token.makeOPENPAR());
				break;
			case ")" :
				que.add(Token.makeCLOSEPAR());
				break;
			case "," :
				que.add(Token.makeCOMMA());
				break;
			case "-" :
				if (que.isEmpty()){
					que.add(Token.makeUNARYMINUS());
					break;
				}
				if (que.getLast().isNumber() || que.getLast().isIdentifier() || (que.getLast().isDelimiter() && que.getLast().getDelimiter().equals(")")) ){
					que.add(Token.makeMINUS());
					break;
				}

				que.add(Token.makeUNARYMINUS());
				break;
			case "*":
				que.add(Token.makeTIMES());
				break;
			case "/":
				que.add(Token.makeDIVIDE());
				break;
			case "^":
				que.add(Token.makePOWER());
				break;
			case "+":
				que.add(Token.makePLUS());
				break;
			default:
				if (isNumeric(str)){
					double num = Double.parseDouble(str);
					que.add(Token.makeNUMBER(num));
					break;
				} else if (str.length() > 3 && str.charAt(0) == '"' && str.charAt(str.length()-1) == '"'){
					que.add(Token.makeSTRING(str));
					break;
				} else if (str.length() > 0 && isWord(str)){
					que.add(Token.makeIDENTIFIER(str));
					break;
				} else{
					throw new LexicalErrorException(str + " is not a valid character");
				}
		}
	}

	//use regex pattern to estimate is number or not.
	public boolean isNumeric(String str){ 
		Pattern pattern = Pattern.compile("[.0-9]+");
		return pattern.matcher(str).matches();
	}

	// use regex pattern to estimate is legal variable or not.
	public static boolean isWord(String str){
        Pattern pattern = Pattern.compile("[a-zA-Z_0-9]+");
		Pattern firstChar = Pattern.compile("[_0-9]");
        return !firstChar.matcher(String.valueOf(str.charAt(0))).matches() && pattern.matcher(str).matches();
    }
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值