Last active
June 10, 2018 16:47
-
-
Save denkspuren/b64bfb06b7b54c9c02fd1e867453a12d to your computer and use it in GitHub Desktop.
Diese Aufgabe verlangt von Ihnen einen Umgang mit Enumerationen, Funktionen, Lambda-Ausdrücken und Strömen
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
In dieser Aufgabe geht es darum, einen als String gegebenen UPN-Ausdruck in | |
einen Stapel von Ergebniswerten zu wandeln. Ein Beispiel: | |
jshell> upn2results.apply("2 3 + 5 4 *", new Stack<Integer>()); | |
$43 ==> [5, 20] | |
Dieser UPN-Rechner arbeitet ausschließlich mit Ganzzahlen. | |
Sie werden durch die Aufgabe geführt. Halten Sie sich bitte an alle Angaben. | |
In dieser Datei sind eine Reihe von `assert`-Anweisungen eingestreut, die den | |
Code testen. | |
Ihr Implementierung ist dann vermutlich korrekt, wenn Sie folgende | |
print-Ausgaben sehen, die nicht von irgendwelchen `assert`-Ausnahmen | |
durchsetzt sind. | |
Cool, you got the tokenizer running | |
Operators ADD and INV are correctly declared! Good job. | |
Hey, you understood how ZERO works! | |
I'm impressed, NUM works as expected! | |
Super, the constructor of Item looks good! | |
With Item.compute things start to fall into place. GREAT! | |
Looks like you succeeded. Congratulations! | |
Rufen Sie die JShell unbedingt mit `jshell -R-ea` auf, ansonsten werden die | |
`assert`-Anweisungen nicht ausgeführt! | |
Füllen Sie die nachfolgenden Code-Fragmente aus. Wenn Sie Ihre Arbeit mit | |
dieser Datei beginnen, kommentieren Sie alles nachfolgende aus, weil die | |
Code-Fragmente so kein gültiger Java-Code sind und zu Abbrüchen und | |
Inkonsistenzen führen. Bisweilen hilft es auch, ein `/reset` in der JShell | |
einzugeben. | |
*/ | |
/* | |
Implementieren Sie die Funktion `tokenize`, die einen als Zeichenkette | |
gegebenen UPN-Ausdruck in seine Bestandteile zerlegt, d.h. die Leerzeichen | |
trennen Zahlen und Operatoren. | |
jshell> tokenize.apply("4 5 * 7 /").collect(Collectors.toList()) | |
$49 ==> [4, 5, *, 7, /] | |
jshell> tokenize.apply("4 5 * 7 /").forEachOrdered(System.out::println) | |
4 | |
5 | |
* | |
7 | |
Die Implementierung ist ein Einzeiler, d.h. sie benötigt ein(!) Semikolon. | |
*/ | |
Function<String,Stream<String>> tokenize = ...; | |
assert tokenize.apply(" Hello World! ").collect(Collectors.toList()).equals(List.of("Hello","World!")); | |
assert tokenize.apply(" 2 4 + 5 4 * * ").collect(Collectors.toList()).equals(List.of("2","4","+","5","4","*","*")); | |
assert tokenize.apply("").collect(Collectors.toList()).equals(List.of("")); | |
System.out.println("Cool, you got the tokenizer running"); | |
/* | |
Erstellen Sie einen Aufzählungstyp `Operator`, der die vorhandenen Operatoren | |
zum Rechnen abbildet. Es soll die zweiwertigen Operatoren `ADD`, `SUB`, `MUL`, | |
`DIV` und `MOD` geben, den einwertigen Operator `INV` und die nullwertigen | |
Operatoren `ZERO` und `NUM`. | |
Die Abkürzungen sind übliche Mnemonics (`ADD` steht z.B. für die Addition, | |
`INV` für die Invertierung, d.h. für den Vorzeichenwechsel). `ZERO` ist ein | |
Operator, der eine Null repräsentiert. `NUM` ist ein besonderer Operator, der | |
für eine Zahl steht. | |
Für die Operatoren soll jeweil angegeben werden, durch welche Zeichenfolge sie | |
repräsentiert werden (Variablenname `repr`), wieviele Argumente der Operator | |
benötigt (Variablennamen `arity`) und wie der Operator als Operation rechnet, | |
wenn die Argumente als Array gegeben sind (eine Funktion mit dem | |
Variablennamen `calculation). | |
Neben dem Konstruktor gibt es eine statische Funktion namens `getOperator`, | |
die zu einer Zeichenkette (der Repräsentation eines Operators) den passenden | |
Operator heraussucht. | |
Eine sorgfältige Auswertung der `assert`-Anweisungen leitet Sie durch die | |
Implementierung. | |
*/ | |
enum Operator { | |
ADD("+",2, args -> args[1] + args[0]), | |
... | |
Operator(String repr, int arity, ...) { | |
... | |
} | |
static Operator getOperator(String s) { | |
... | |
} | |
} | |
assert Operator.getOperator("+") != null; | |
assert Operator.getOperator("+").name().equals("ADD"); | |
assert Operator.ADD.arity == 2; | |
assert Operator.ADD.calculation.apply(new Integer[] {2,3}) == 5; | |
assert Operator.getOperator("~") != null; | |
assert Operator.getOperator("~").name().equals("INV"); | |
assert Operator.INV.arity == 1; | |
assert Operator.INV.calculation.apply(new Integer[] {1}) == -1; | |
System.out.println("Operators ADD and INV are correctly declared! Good job.") | |
assert Operator.getOperator("ZERO") != null; | |
assert Operator.getOperator("ZERO").name().equals("ZERO"); | |
assert Operator.ZERO.arity == 0; | |
assert Operator.ZERO.calculation.apply(new Integer[0]) == 0; | |
System.out.println("Hey, you understood how ZERO works!"); | |
assert Operator.getOperator("") != null; | |
assert Operator.getOperator("").name().equals("NUM"); | |
assert Operator.ZERO.arity == 0; | |
assert Operator.ZERO.calculation.apply(new Integer[0]) instanceof Integer; | |
System.out.println("I'm impressed, NUM works as expected!"); | |
/* | |
Der durch den `tokenizer` generierte Zeichenkettenstrom soll später | |
in einem ersten Durchlauf abgebildet werden auf einen Strom von Items. | |
Dafür wird die Klasse `Item` benötigt. | |
Die Klasse `Item` bekommt im Konstruktor eine Zeichenkette geliefert und | |
legt intern im erzeugten Objekt in der Variable `operator` den Operator | |
ab und -- wenn der Operator ein ´NUM` ist -- den Ganzzahlwert der | |
Zeichenkette in einer Variable namens `value` ab. | |
Die Methode `compute` erwartet einen Stapel mit Ganzzahlen, wendet die | |
zum Operator gespeicherte Rechenoperation des Items an (außer bei NUM, | |
da wird der Zahlenwert auf den Stapel gepusht) und legt das Ergebnis | |
auf den Stapel ab. | |
Im Rumpf der Referenzimplementierung kommen insgesamt 11 Semikolons zum | |
Einsatz. | |
*/ | |
class Item { | |
... | |
Item(String s) throws NumberFormatException { | |
... | |
} | |
Stack<Integer> compute(Stack<Integer> stack) { | |
... | |
} | |
} | |
// Ignorieren Sie die Funktion: helper function for testing purposes | |
Function<List<Integer>,Stack<Integer>> stackify = lst -> { | |
Stack<Integer> stack = new Stack<>(); | |
lst.stream().forEachOrdered(stack::push); | |
return stack; | |
} | |
assert new Item("ZERO").operator == Operator.ZERO; | |
assert new Item("234").operator == Operator.NUM; | |
assert new Item("0").value == 0; | |
assert new Item("-10").value == -10; | |
System.out.println("Super, the constructor of Item looks good!"); | |
assert new Item("ZERO").compute(new Stack<Integer>()).equals(List.of(0)); | |
assert new Item("123").compute(new Stack<Integer>()).equals(List.of(123)); | |
assert new Item("/").compute(stackify.apply(List.of(2,12,3))).equals(List.of(2,4)); | |
assert new Item("~").compute(stackify.apply(List.of(7,14))).equals(List.of(7,-14)); | |
System.out.println("With Item.compute things start to fall into place. GREAT!"); | |
/* | |
Sie haben es fast geschafft! Es fehlt nur noch die Umsetzung der Funktion | |
`upn2results`. | |
Der Funktion wird ein UPN-Ausdruck als Zeichenkette und ein Stapel übergeben. | |
Zurück kommt ein Stapel, auf dem die Ergebnisse der Auswertung zusätzlich | |
abgelegt sind. | |
Die Referenzimplementierung kommt mit zwei Semikolons aus! | |
*/ | |
... upn2results = ...; | |
assert upn2results.apply("2 3 +", new Stack<Integer>()).equals(List.of(5)); // pop() == 5; | |
assert upn2results.apply("2 3 -", new Stack<Integer>()).equals(List.of(-1)); // pop() == -1; | |
assert upn2results.apply("2 3 + 4 * 2 3 -", new Stack<Integer>()).equals(List.of(20,-1)); | |
assert upn2results.apply("2 3 + 4 * 2 3 ~ +", new Stack<Integer>()).equals(List.of(20,-1)); | |
assert upn2results.apply("ZERO ZERO + ZERO *", new Stack<Integer>()).equals(List.of(0)); | |
System.out.println("Looks like you succeeded. Congratulations!"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment