001 package de.hska.java.aufgaben.rekursion;
002
003 /**
004 * Implementiert einen sehr einfachen Taschenrechner mit einem
005 * Parser auf Basis des rekursiven Abstiegs.
006 * Die zugrundliegende Grammatik in EBNF ist
007 * <pre>
008 * ausdruck = term, [ "+" | "-" , term ] ;
009 * term = "(", term, ")" | "0" | "1" | ... | "9" ;
010 * </pre>
011 * <p>
012 * <a href="http://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/rekursion.html#taschenrechner">Zurück zum Aufgabentext</a>
013 * </p>
014 *
015 * @author Christian Pape
016 *
017 */
018 public class Taschenrechner {
019
020 private char[] ausdruck;
021
022 private char aktuellesZeichen;
023
024 private int indexAktuellesZeichen = 0;
025
026 /**
027 * Erzeugt einen neuen Taschenrechner mit dem gegebenen
028 * auszuwertenden Ausdruck.
029 */
030 public Taschenrechner(String ausdruck) {
031 this.ausdruck = ausdruck.toCharArray();
032 naechstesZeichenEinlesen();
033 }
034
035 /**
036 * Liesst das nächste Zeichen ein. Falls keins mehr existiert,
037 * dann ist das Zeichen 0. Leerzeichen werden überlesen.
038 */
039 private void naechstesZeichenEinlesen() {
040 while ( indexAktuellesZeichen < ausdruck.length
041 && Character.isWhitespace(ausdruck[indexAktuellesZeichen]) ) {
042 indexAktuellesZeichen++;
043 }
044
045 if ( indexAktuellesZeichen < ausdruck.length) {
046 aktuellesZeichen = ausdruck[indexAktuellesZeichen++];
047 } else {
048 aktuellesZeichen = 0;
049 }
050 }
051
052 /**
053 * Gibt den Wert des Ausdrucks zurück.
054 */
055 public int evaluiereAusdruck() {
056 int ergebnis = evaluiereTerm();
057
058 while ( aktuellesZeichen == '+' || aktuellesZeichen == '-') {
059 char operator = aktuellesZeichen;
060 naechstesZeichenEinlesen();
061 int term = evaluiereTerm();
062 switch (operator) {
063 case '+': ergebnis += term;
064 break;
065 case '-': ergebnis -= term;
066 break;
067 }
068 }
069
070 return ergebnis;
071 }
072
073 /**
074 * Liesst einen Term ein und gibt den Wert zurück.
075 * Ein Term ist ein geklammerter Term oder eine Ziffer.
076 */
077 private int evaluiereTerm() {
078 int ergebnis = 0;
079
080 if (aktuellesZeichen == '(') {
081 naechstesZeichenEinlesen();
082 ergebnis = evaluiereAusdruck();
083 if (aktuellesZeichen != ')') {
084 System.out.println("Schliessende Klammer erwartet");
085 } else {
086 naechstesZeichenEinlesen();
087 }
088 } else if ( Character.isDigit(aktuellesZeichen)) {
089 ergebnis = aktuellesZeichen - '0';
090 naechstesZeichenEinlesen();
091 }
092
093 return ergebnis;
094 }
095 }