import java.util.Scanner; import java.text.DecimalFormat; /** * Hauptklasse des Projekts */ public class Rechenmaschine { private List tokenlist; private String fehler; private String result; private int klammern; public Rechenmaschine(String eingabe) { tokenlist = new List<>(); 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 '+', '-' -> { tokenlist.append(new Token("OPERATOR", Character.toString(buchstabe))); state = 5; } 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 = 2; 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; break; } else { fehler = "Unbekanntes Token: " + currentToken.getType(); return false; } case 2: if (currentToken.getType().equals("OPERATOR")) { state = 0; break; } else if (currentToken.getType().equals("OPERAND")) { state = 1; break; } else if (currentToken.getToken().equals("(")) { state = 2; break; } else if (currentToken.getToken().equals(")")) { state = 1; break; } 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(List pList) { 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(List pList) { 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(List pList) { 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); this.result= resultString; } public String getResult() { return result; } }