import java.util.Scanner; import java.text.DecimalFormat; /** * Hauptklasse des Projekts */ public class Rechenmaschine { public static void main(String[] args) { new Rechenmaschine(); } private List tokenlist; private String fehler; private double result; private int klammern; public Rechenmaschine() { tokenlist = new List<>(); Scanner input = new Scanner(System.in); System.out.println("Gib einen Term ein und bestätige mit ENTER: "); String eingabe = input.nextLine(); input.close(); if( !scanne(eingabe) ) { System.out.println("Fehler bei der lexikalischen Analyse:"); System.out.println(fehler); return; } if( !parse() ) { System.out.println("Fehler bei der syntaktischen Analyse:"); System.out.println(fehler); return; } if( !analyse() ) { System.out.println("Fehler bei der semantischen Analyse:"); System.out.println(fehler); return; } run(); } public boolean scanne( String pEingabe ) { char[] eingabe = pEingabe.toCharArray(); klammern = 0; int state = 0; StringBuilder currentToken = new StringBuilder(); for(char buchstabe: eingabe){ switch(state){ case 0: switch (buchstabe) { case '0' -> { currentToken.append(buchstabe); state = 1; } case '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { currentToken.append(buchstabe); state = 2; } case '.' -> { System.out.println("Am anfang des Termes kann kein . stehen."); return false; } case '+', '-', '*', '/' -> { System.out.println("Der Term darf nicht mir mit dem Operator " + buchstabe + " beginnen."); return false; } case '(' -> { tokenlist.append(new Token("PARANTHESES",Character.toString(buchstabe))); state = 6; klammern++; } case ')' -> { System.out.println("Der Term darf nicht mit ) beginnen"); return false; } default -> { System.out.println("Der Buchstabe " + buchstabe + " ist nicht in der Sprache vorhanden."); return false; } } break; case 1: switch (buchstabe) { case '0','1', '2', '3', '4', '5', '6', '7', '8', '9' -> { System.out.println("Wenn eine 0 am anfang eines Operands ist, muss ein . folgen."); return false; } case '.' -> { currentToken.append(buchstabe); state = 3; } case '+', '-', '*', '/' -> { tokenlist.append(new Token("OPERAND", currentToken.toString())); currentToken = new StringBuilder(); tokenlist.append(new Token("OPERATOR", Character.toString(buchstabe))); state = 5; } case ')' -> { tokenlist.append(new Token("OPERAND",currentToken.toString())); currentToken = new StringBuilder(); tokenlist.append(new Token("PARANTHESES",")")); state = 7; klammern--; } case '(' -> { System.out.println("Mach einem Operand darf nicht unmittelbar ein ( folgen"); return false; } default -> { System.out.println("Der Buchstabe " + buchstabe + " ist nicht in der Sprache vorhanden."); return false; } } break; case 2: switch (buchstabe) { case '.' -> { currentToken.append(buchstabe); state = 3; } case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { currentToken.append(buchstabe); state = 2; } case '+', '-', '*', '/' -> { tokenlist.append(new Token("OPERAND", currentToken.toString())); currentToken = new StringBuilder(); tokenlist.append(new Token("OPERATOR", Character.toString(buchstabe))); state = 5; } case ')' -> { tokenlist.append(new Token("OPERAND",currentToken.toString())); currentToken = new StringBuilder(); tokenlist.append(new Token("PARANTHESES",")")); state = 7; klammern--; } case '(' -> { System.out.println("Nach einem Operand darf nicht unmittelbar ein ( folgen."); return false; } default -> { System.out.println("Der Buchstabe " + buchstabe + " ist nicht in der Sprache vorhanden."); return false; } } break; case 3: switch (buchstabe) { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { currentToken.append(buchstabe); state = 4; } case '+', '-', '*', '/', '(', ')' -> { System.out.println("Nach einem . darf kein Rechenoperator, oder eine Klammer folgen"); return false; } } break; case 4: switch (buchstabe) { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { currentToken.append(buchstabe); state = 4; } case '+', '-', '*', '/' -> { tokenlist.append(new Token("OPERAND", currentToken.toString())); currentToken = new StringBuilder(); tokenlist.append(new Token("OPERATOR", Character.toString(buchstabe))); state = 5; } case '.' -> { System.out.println("Eine Dezimalzahl kann nur ein . haben."); return false; } case ')' -> { tokenlist.append(new Token("OPERAND",currentToken.toString())); currentToken = new StringBuilder(); tokenlist.append(new Token("PARANTHESES",Character.toString(buchstabe))); state = 7; klammern--; } case '(' -> { System.out.println("Nach einem Operand darf nicht unmittelbar ein ( folgen."); return false; } default -> { System.out.println("Der Buchstabe " + buchstabe + " ist nicht in der Sprache vorhanden."); return false; } } break; case 5: switch (buchstabe) { case '0' -> { currentToken.append(buchstabe); state = 1; } case '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { currentToken.append(buchstabe); state = 2; } case '.' -> { System.out.println("Nach einem Operator kann kein . stehen."); return false; } case '+', '-', '*', '/' -> { System.out.println("Nach einem Operator darf nicht direkt ein weiterer Operator folgen."); return false; } case '(' -> { tokenlist.append(new Token("PARANTHESES","(")); state = 6; klammern++; } case ')' -> { System.out.println("Nach einem Operator darf kein ) folgen."); return false; } default -> { System.out.println("Der Buchstabe " + buchstabe + " ist nicht in der Sprache vorhanden."); return false; } } break; case 6: switch(buchstabe) { case '0' -> { currentToken.append(buchstabe); state = 1; } case '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { currentToken.append(buchstabe); state = 2; } case '+', '-', '*', '/' -> { System.out.println("Unmittelbar nach ( darf kein Operator oder ) folgen."); return false; } case '(' -> { tokenlist.append(new Token("PARANTHESES",Character.toString(buchstabe))); klammern++; } default -> { System.out.println("Der Buchstabe " + buchstabe + " ist nicht in der Sprache vorhanden."); return false; } } break; case 7: switch(buchstabe) { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '(' -> { System.out.println("Nach ) muss ein Operator folgen"); return false; } case '+', '-', '*', '/' -> { tokenlist.append(new Token("OPERATOR",Character.toString(buchstabe))); state = 5; } case ')' -> { tokenlist.append(new Token("PARANTHESES",Character.toString(buchstabe))); klammern--; } default -> { System.out.println("Der Buchstabe " + buchstabe + " ist nicht in der Sprache vorhanden."); return false; } } break; } } if( state == 5 ) { fehler = "Fehler im Wort " +pEingabe+ ":\nDas Wort darf nicht mit einem Operator enden!"; return false; } else if (state == 3){ fehler = "Fehler im Wort " +pEingabe+ ":\nDas Wort darf nicht mit einem . enden!"; return false; } else if (state ==6){ fehler = "Fehler im Wort " +pEingabe+ ":\nDas Wort darf nicht mit ( enden!"; return false; } else if (klammern !=0){ fehler = "Fehler im Wort " +pEingabe+ ":\nIm wort müssen alle Klammern geschlossen sein!"; return false; } else { tokenlist.toLast(); if (tokenlist.hasAccess()) { if (!tokenlist.getContent().getToken().equals(")")) { tokenlist.append(new Token("OPERAND", currentToken.toString())); } } else { tokenlist.append(new Token("OPERAND", currentToken.toString())); } return true; } } public boolean parse() { int state = 0; tokenlist.toFirst(); while( tokenlist.hasAccess() ) { Token currentToken = tokenlist.getContent(); switch( state ) { case 0: if( currentToken.getType().equals("OPERATOR") ) { fehler = "Rechenterm darf nicht mit einem Operator starten!"; return false; } else if( currentToken.getType().equals("OPERAND") ) { state = 1; break; } else if( currentToken.getToken().equals("(")){ state = 0; break; } else if( currentToken.getToken().equals(")")){ state = 1; break; } else { fehler = "Unbekanntes Token: "+currentToken.getType(); return false; } case 1: if( currentToken.getType().equals("OPERATOR") ) { state = 0; break; } else if( currentToken.getType().equals("OPERAND") ) { fehler = "Auf einen Operanden darf kein Operand folgen!"; return false; } else if( currentToken.getToken().equals("(") ) { fehler = "Auf einen Operanden kann kein ( folgen"; return false; } else if( currentToken.getToken().equals(")")) { state = 1; } else { fehler = "Unbekanntes Token: "+currentToken.getType(); return false; } } tokenlist.next(); } if( state == 0 ) { fehler = "Ein Rechenterm darf nicht auf einen Operator enden!"; return false; } else { return true; } } public boolean analyse() { tokenlist.toFirst(); while(tokenlist.hasAccess()){ if(tokenlist.getContent().getToken().equals("/")){ tokenlist.next(); if(tokenlist.getContent().getToken().equals("0")){ fehler = "Es kann nicht durch 0 geteilt werden."; return false; } } tokenlist.next(); } return true; } private void punktVorStrich(ListpList){ pList.toFirst(); while(pList.hasAccess()){ if(pList.getContent().getToken().equals("*")){ pList.remove(); Double faktor1 = Double.parseDouble(pList.getContent().getToken()); pList.current=pList.getPrevious(pList.current); Double faktor2 = Double.parseDouble(pList.getContent().getToken()); pList.remove(); pList.getContent().setToken(String.valueOf(faktor2*faktor1)); } else if(pList.getContent().getToken().equals("/")){ pList.remove(); Double divisor = Double.parseDouble(pList.getContent().getToken()); //Previous Token muss gelöscht werden, tokenlist.getContent != null ist, // wenn der 2. Token am ende des Termes ist. pList.current=pList.getPrevious(pList.current); Double dividend = Double.parseDouble(pList.getContent().getToken()); pList.remove(); pList.getContent().setToken(String.valueOf(dividend/divisor)); } pList.next(); } } private void klammerRegel(ListpList){ List newTokenlist= new List(); pList.toFirst(); double berechnet; //Durchlaufe die Tokenliste while(pList.hasAccess()){ // Token gleich ( dann entferne ihn if(pList.getContent().getToken().equals("(")) { pList.remove(); //anschließend durchlaufe solange, bis auf ) gestoßen wird while (!pList.getContent().getToken().equals(")")) { //wenn noch nicht am ende der tokenliste if (pList.hasAccess()) { //wenn ( erneutvorkommt if (pList.getContent().getToken().equals("(")) { // rufe die methode mehrereKlammern auf und speicher das ergebnis als neues Token in newTokenlist berechnet = mehrereKlammern(pList); newTokenlist.append(new Token("OPERAND", String.valueOf(berechnet))); } //wenn der Token nicht ) ist dann soll dieser in newTokenlist eingefügt werden und anschließend entfernt werden if (!pList.getContent().getToken().equals(")")) { newTokenlist.append(pList.getContent()); pList.remove(); } } } //wenn auf ) gestoßen wurde, soll ) entfernt werden pList.remove(); //newTokenlist wird ausgerechnet berechnet = berechne(newTokenlist); //und in die Tokenliste eingefügt if (pList.hasAccess()) { pList.insert(new Token("OPERAND", String.valueOf(berechnet))); } else { pList.append(new Token("OPERAND", String.valueOf(berechnet))); } newTokenlist = new List(); //hier wurde nun 1 klammer gelöst } //wenn die liste noch nicht zu ende ist, soll das nächste Element geprüft werden pList.next(); } } private double mehrereKlammern(ListpList){ List newTokenlist= new List(); double berechnet=0; //wenn current ( ist if(pList.getContent().getToken().equals("(")){ //wird es entfernt pList.remove(); //anschließend wird die übergebene tokenliste solange durchlaufen, bis ) auftritt while(!pList.getContent().getToken().equals(")")){ if(pList.hasAccess()) { //wenn current ( ist dann wird diese methode nochmal ab current ausgeführt und anschließend // das ergebnis in newTokenlist eingefügt if (pList.getContent().getToken().equals("(") ) { berechnet = mehrereKlammern(pList); newTokenlist.append(new Token("OPERAND",String.valueOf(berechnet))); } // wenn current nich ) ist, dann wird es in newTokenlist gespeichert und aus der tokenliste entfernt if (!pList.getContent().getToken().equals(")")) { newTokenlist.append(pList.getContent()); pList.remove(); } } } //wenn ) auftritt dann wird es entfernt und anschließend wird die berechnung von newTokenlist rückgegeben. pList.remove(); berechnet = berechne(newTokenlist); } return berechnet; } private double berechne(List pList){ double result1 = 0; punktVorStrich(pList); pList.toFirst(); String previous=""; while( pList.hasAccess() ) { Token currentToken = pList.getContent(); if(currentToken.getType().equals("OPERATOR")){ previous=currentToken.getToken(); } if( currentToken.getType().equals("OPERAND") ) { switch (previous) { case "+", "" -> result1 += Double.parseDouble(currentToken.getToken()); case "-" -> result1 -= Double.parseDouble(currentToken.getToken()); } } pList.next(); } return result1; } public void run() { klammerRegel(tokenlist); punktVorStrich(tokenlist); double result=berechne(tokenlist); DecimalFormat format = new DecimalFormat("#,##0.####"); String resultString=format.format(result); System.out.println("Ergebnis der Ausführung: " + resultString); } }