| @@ -6,11 +6,14 @@ | |||||
| package expression; | package expression; | ||||
| /*! | /*! | ||||
| Eine `Addition` besteht aus einer `leftHandSide` und einer `rightHandSide`, die addiert werden sollen. | |||||
| An `Addition` consists of a `leftHandSide` and a `rightHandSide` expression, which are supposed to be added. | |||||
| For example | |||||
| Zum Beispiel | |||||
| new Addition(new Identifier("x"), new Int(2)) | new Addition(new Identifier("x"), new Int(2)) | ||||
| repräsentiert den Ausdruck | |||||
| represents the code | |||||
| x + 2 | x + 2 | ||||
| */ | */ | ||||
| public class Addition extends Expression { | public class Addition extends Expression { | ||||
| @@ -22,12 +25,13 @@ public class Addition extends Expression { | |||||
| this.rightHandSide = rightHandSide; | this.rightHandSide = rightHandSide; | ||||
| } | } | ||||
| /*!- Hilfsmethoden */ | |||||
| /*!- String serialization */ | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return "(" + leftHandSide + " + " + rightHandSide + ")"; | return "(" + leftHandSide + " + " + rightHandSide + ")"; | ||||
| } | } | ||||
| /*!- Generated equals implementation */ | |||||
| @Override | @Override | ||||
| public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
| if (this == o) return true; | if (this == o) return true; | ||||
| @@ -39,11 +43,4 @@ public class Addition extends Expression { | |||||
| return rightHandSide.equals(addition.rightHandSide); | return rightHandSide.equals(addition.rightHandSide); | ||||
| } | } | ||||
| @Override | |||||
| public int hashCode() { | |||||
| int result = leftHandSide.hashCode(); | |||||
| result = 31 * result + rightHandSide.hashCode(); | |||||
| return result; | |||||
| } | |||||
| } | } | ||||
| @@ -1,4 +1,9 @@ | |||||
| /*!! Expression*/ | |||||
| /*! # Expression*/ | |||||
| /*!- Header */ | |||||
| package expression; | package expression; | ||||
| abstract public class Expression { | |||||
| } | |||||
| /*! `Expression` is the common abstract class for Expressions that can be evaluated using the `Evaluator`. */ | |||||
| abstract public class Expression { } | |||||
| @@ -1,30 +1,34 @@ | |||||
| package expression; | |||||
| /*!! Expression*/ | |||||
| public class Identifier extends Expression { | |||||
| @Override | |||||
| public boolean equals(Object o) { | |||||
| if (this == o) return true; | |||||
| if (o == null || getClass() != o.getClass()) return false; | |||||
| /*! # Identifier*/ | |||||
| Identifier that = (Identifier) o; | |||||
| /*! Header*/ | |||||
| package expression; | |||||
| return name.equals(that.name); | |||||
| /*! An `Identifier` consists only of the `name` of the identifier. This class is only needed as a wrapper which allows | |||||
| us to use an identifier as an expression. */ | |||||
| public class Identifier extends Expression { | |||||
| public final String name; | |||||
| public Identifier(String name) { | |||||
| this.name = name; | |||||
| } | } | ||||
| /*!- String serialization */ | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return name; | return name; | ||||
| } | } | ||||
| /*!- generated equals implementation */ | |||||
| @Override | @Override | ||||
| public int hashCode() { | |||||
| return name.hashCode(); | |||||
| } | |||||
| public boolean equals(Object o) { | |||||
| if (this == o) return true; | |||||
| if (o == null || getClass() != o.getClass()) return false; | |||||
| public final String name; | |||||
| Identifier that = (Identifier) o; | |||||
| return name.equals(that.name); | |||||
| public Identifier(String name) { | |||||
| this.name = name; | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,5 +1,14 @@ | |||||
| /*!! Expression*/ | |||||
| /*! # Int */ | |||||
| /*!- Header */ | |||||
| package expression; | package expression; | ||||
| /*! | |||||
| An `Int` consists only of its `value`. This class is only needed as a wrapper which allows | |||||
| us to use an integer as an expression. | |||||
| */ | |||||
| public class Int extends Expression { | public class Int extends Expression { | ||||
| public final int value; | public final int value; | ||||
| @@ -7,6 +16,13 @@ public class Int extends Expression { | |||||
| this.value = value; | this.value = value; | ||||
| } | } | ||||
| /*!- String serialization */ | |||||
| @Override | |||||
| public String toString() { | |||||
| return Integer.toString(value); | |||||
| } | |||||
| /*!- generated equals implementation */ | |||||
| @Override | @Override | ||||
| public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
| if (this == o) return true; | if (this == o) return true; | ||||
| @@ -15,16 +31,5 @@ public class Int extends Expression { | |||||
| Int integer = (Int) o; | Int integer = (Int) o; | ||||
| return value == integer.value; | return value == integer.value; | ||||
| } | |||||
| @Override | |||||
| public String toString() { | |||||
| return Integer.toString(value); | |||||
| } | |||||
| @Override | |||||
| public int hashCode() { | |||||
| return value; | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,9 +1,37 @@ | |||||
| /*!! Expression */ | |||||
| /*! # Subtraction */ | |||||
| /*!- Header */ | |||||
| package expression; | package expression; | ||||
| /*! | |||||
| A `Subtraction` consists of a `leftHandSide` and a `rightHandSide` expression, which are supposed to be subtracted. | |||||
| For example | |||||
| new Subtraction(new Identifier("x"), new Int(2)) | |||||
| represents the code | |||||
| x - 2 | |||||
| */ | |||||
| public class Subtraction extends Expression { | public class Subtraction extends Expression { | ||||
| public final Expression leftHandSide; | public final Expression leftHandSide; | ||||
| public final Expression rightHandSide; | public final Expression rightHandSide; | ||||
| public Subtraction(Expression leftHandSide, Expression rightHandSide) { | |||||
| this.leftHandSide = leftHandSide; | |||||
| this.rightHandSide = rightHandSide; | |||||
| } | |||||
| /*!- String serialization */ | |||||
| @Override | |||||
| public String toString() { | |||||
| return "(" + leftHandSide + " - " + rightHandSide + ")"; | |||||
| } | |||||
| /*!- generated equals implementation */ | |||||
| @Override | @Override | ||||
| public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
| if (this == o) return true; | if (this == o) return true; | ||||
| @@ -15,21 +43,4 @@ public class Subtraction extends Expression { | |||||
| return rightHandSide.equals(that.rightHandSide); | return rightHandSide.equals(that.rightHandSide); | ||||
| } | } | ||||
| @Override | |||||
| public String toString() { | |||||
| return "(" + leftHandSide + " - " + rightHandSide + ")"; | |||||
| } | |||||
| @Override | |||||
| public int hashCode() { | |||||
| int result = leftHandSide.hashCode(); | |||||
| result = 31 * result + rightHandSide.hashCode(); | |||||
| return result; | |||||
| } | |||||
| public Subtraction(Expression leftHandSide, Expression rightHandSide) { | |||||
| this.leftHandSide = leftHandSide; | |||||
| this.rightHandSide = rightHandSide; | |||||
| } | |||||
| } | } | ||||
| @@ -1,7 +1,12 @@ | |||||
| /*!! Parser */ | /*!! Parser */ | ||||
| /*! | /*! | ||||
| # Parser | # Parser | ||||
| Dieser [rekursiv absteigende Parser](https://de.wikipedia.org/wiki/Rekursiver_Abstieg) versteht sehr einfache While-Programme, die folgender Grammatik in [EBNF](https://de.wikipedia.org/wiki/Erweiterte_Backus-Naur-Form) genügen: | |||||
| In order to parse simple while programs we use a | |||||
| [Recursive descent parser](https://en.wikipedia.org/wiki/Recursive_descent_parser). The syntax of our while programs | |||||
| are defined by the following grammar in | |||||
| [Extended Backus-Naur Form (EBNF)](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form): | |||||
| Prog = Id ":=" Expr | | Prog = Id ":=" Expr | | ||||
| Prog ";" Prog | | Prog ";" Prog | | ||||
| @@ -12,10 +17,10 @@ Dieser [rekursiv absteigende Parser](https://de.wikipedia.org/wiki/Rekursiver_Ab | |||||
| Atom | Atom | ||||
| Atom = Id | Num | "(" Expr ")" | Atom = Id | Num | "(" Expr ")" | ||||
| Dabei kann `Num` direkt zu einer beliebigen ganzen Zahl und `Id` direkt zu einem beliebigen Bezeichner aus den Zeichen | |||||
| `a` bis `z` abgeleitet werden. | |||||
| The non-terminal `Num` can be derived into an arbitrary integer. `Id` can be derived into an arbitrary identifier | |||||
| consisting of the lower case characters from `a` to `z`. | |||||
| Der Parser nimmt einen String mit dem Quelltext entgegen und erzeugt daraus ein `Program`. | |||||
| Our parser takes the source code as argument and returns a `Program` object. | |||||
| */ | */ | ||||
| /*!- Header */ | /*!- Header */ | ||||
| @@ -29,26 +34,27 @@ import java.util.ArrayList; | |||||
| import java.util.List; | import java.util.List; | ||||
| /*! | /*! | ||||
| Die Klasse `Parser` implementiert den Parser. Sie wird verwendet, indem dem Konstruktor der zu parsende Quelltext | |||||
| übergeben wird. Anschließend kann die Methide `parse` aufgerufen werden, die das geparste `Program` zurückgibt. | |||||
| `Parser` provides a constructor which takes the source code as argument. The created object provides the method | |||||
| `parse` which returns the parsed `Program` object. | |||||
| Parser parser = new Parser("a := 1"); | Parser parser = new Parser("a := 1"); | ||||
| Program program = parser.parse(); | Program program = parser.parse(); | ||||
| */ | */ | ||||
| public class Parser { | public class Parser { | ||||
| /*! | |||||
| Die Instanzvariable `input` hält den zu parsenden Quelltext und in `position` steht die aktuelle Position des Parsers. | |||||
| Alle folgenden Methoden betrachten den Quelltext jeweils ab der aktuellen Position und erhöhen diese, wenn Zeichen | |||||
| des Quelltextes geparsed wurden. | |||||
| */ | |||||
| /*! | |||||
| The instance variable `input` contains the source code that should be parsed and `position` contains the current | |||||
| position of the parser in the `input` string. The following parsing methods each consider the characters of the | |||||
| `input` starting at `position`, e.g. `input.charAt(position)`. After consuming characters of the input the methods | |||||
| increment the `position`. | |||||
| */ | |||||
| int position; | int position; | ||||
| String input; | |||||
| final String input; | |||||
| public Parser(String input) { | public Parser(String input) { | ||||
| this.input = input; | this.input = input; | ||||
| } | } | ||||
| public Program parse() { | public Program parse() { | ||||
| position = 0; | position = 0; | ||||
| Program program = program(); | Program program = program(); | ||||
| @@ -1,38 +1,49 @@ | |||||
| /*!! Program*/ | |||||
| /*! # Program */ | |||||
| /*!- Header */ | |||||
| package program; | package program; | ||||
| import expression.Expression; | import expression.Expression; | ||||
| import expression.Identifier; | import expression.Identifier; | ||||
| public class Assignment extends Program { | |||||
| public final Identifier identifier; | |||||
| public final Expression expression; | |||||
| /*! An `Assignment` consists of an `identifier` and an `expression` which should be evaluated and the result stored | |||||
| in the variable named by the identifier. | |||||
| @Override | |||||
| public boolean equals(Object o) { | |||||
| if (this == o) return true; | |||||
| if (o == null || getClass() != o.getClass()) return false; | |||||
| For example | |||||
| Assignment that = (Assignment) o; | |||||
| new Assignment(new Identifier("x"), new Number(5)) | |||||
| if (!identifier.equals(that.identifier)) return false; | |||||
| return expression.equals(that.expression); | |||||
| represents the code | |||||
| x := 5 | |||||
| */ | |||||
| public class Assignment extends Program { | |||||
| public final Identifier identifier; | |||||
| public final Expression expression; | |||||
| public Assignment(Identifier identifier, Expression expression) { | |||||
| this.identifier = identifier; | |||||
| this.expression = expression; | |||||
| } | } | ||||
| /*!- String serialization */ | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return identifier + " := " + expression; | return identifier + " := " + expression; | ||||
| } | } | ||||
| /*!- generated equals method*/ | |||||
| @Override | @Override | ||||
| public int hashCode() { | |||||
| int result = identifier.hashCode(); | |||||
| result = 31 * result + expression.hashCode(); | |||||
| return result; | |||||
| } | |||||
| public boolean equals(Object o) { | |||||
| if (this == o) return true; | |||||
| if (o == null || getClass() != o.getClass()) return false; | |||||
| public Assignment(Identifier identifier, Expression expression) { | |||||
| this.identifier = identifier; | |||||
| this.expression = expression; | |||||
| Assignment that = (Assignment) o; | |||||
| if (!identifier.equals(that.identifier)) return false; | |||||
| return expression.equals(that.expression); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,35 +1,36 @@ | |||||
| /*!! Program*/ | |||||
| /*! # Composition*/ | |||||
| /*!- Header*/ | |||||
| package program; | package program; | ||||
| /*! A `Composition` combines two programs (`first` and `second`) with the intended semantics of sequential | |||||
| composition. */ | |||||
| public class Composition extends Program { | public class Composition extends Program { | ||||
| public final Program first; | public final Program first; | ||||
| public final Program second; | public final Program second; | ||||
| @Override | |||||
| public boolean equals(Object o) { | |||||
| if (this == o) return true; | |||||
| if (o == null || getClass() != o.getClass()) return false; | |||||
| Composition that = (Composition) o; | |||||
| if (!first.equals(that.first)) return false; | |||||
| return second.equals(that.second); | |||||
| public Composition(Program first, Program second) { | |||||
| this.first = first; | |||||
| this.second = second; | |||||
| } | } | ||||
| /*!- String serialization */ | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return first + " ; " + second; | return first + " ; " + second; | ||||
| } | } | ||||
| /*!- generated equals implementation */ | |||||
| @Override | @Override | ||||
| public int hashCode() { | |||||
| int result = first.hashCode(); | |||||
| result = 31 * result + second.hashCode(); | |||||
| return result; | |||||
| } | |||||
| public boolean equals(Object o) { | |||||
| if (this == o) return true; | |||||
| if (o == null || getClass() != o.getClass()) return false; | |||||
| public Composition(Program first, Program second) { | |||||
| this.first = first; | |||||
| this.second = second; | |||||
| Composition that = (Composition) o; | |||||
| if (!first.equals(that.first)) return false; | |||||
| return second.equals(that.second); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,12 +1,26 @@ | |||||
| /*!! Program*/ | |||||
| /*! # Conditional*/ | |||||
| /*!- Header*/ | |||||
| package program; | package program; | ||||
| import expression.Expression; | import expression.Expression; | ||||
| /*! A `Conditional` consists of the `condition` expression and the two programs `thenCase` and `elseCase` with the | |||||
| intended semantics of execution the `elseCase` if the `expression` evaluates to 0 and the `thenCase` otherwise. */ | |||||
| public class Conditional extends Program { | public class Conditional extends Program { | ||||
| public final Expression condition; | public final Expression condition; | ||||
| public final Program thenCase; | public final Program thenCase; | ||||
| public final Program elseCase; | public final Program elseCase; | ||||
| public Conditional(Expression condition, Program thenCase, Program elseCase) { | |||||
| this.condition = condition; | |||||
| this.thenCase = thenCase; | |||||
| this.elseCase = elseCase; | |||||
| } | |||||
| /*!- generated equals implementation */ | |||||
| @Override | @Override | ||||
| public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
| if (this == o) return true; | if (this == o) return true; | ||||
| @@ -20,22 +34,9 @@ public class Conditional extends Program { | |||||
| } | } | ||||
| /*!- String serialization*/ | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return "if (" + condition + ") then { " + thenCase + " } else { " + elseCase + " }"; | return "if (" + condition + ") then { " + thenCase + " } else { " + elseCase + " }"; | ||||
| } | } | ||||
| @Override | |||||
| public int hashCode() { | |||||
| int result = condition.hashCode(); | |||||
| result = 31 * result + thenCase.hashCode(); | |||||
| result = 31 * result + elseCase.hashCode(); | |||||
| return result; | |||||
| } | |||||
| public Conditional(Expression condition, Program thenCase, Program elseCase) { | |||||
| this.condition = condition; | |||||
| this.thenCase = thenCase; | |||||
| this.elseCase = elseCase; | |||||
| } | |||||
| } | } | ||||
| @@ -1,7 +1,14 @@ | |||||
| /*!! Program*/ | |||||
| /*! # Loop */ | |||||
| /*!- Header*/ | |||||
| package program; | package program; | ||||
| import expression.Expression; | import expression.Expression; | ||||
| /*! A `Loop` consists of a `condition` and a `program` with the intended semantics of execution the `program` while | |||||
| the `condition` evaluates to a non-zero value. */ | |||||
| public class Loop extends Program { | public class Loop extends Program { | ||||
| public final Expression condition; | public final Expression condition; | ||||
| public final Program program; | public final Program program; | ||||
| @@ -11,6 +18,13 @@ public class Loop extends Program { | |||||
| this.program = program; | this.program = program; | ||||
| } | } | ||||
| /*!- String serialization */ | |||||
| @Override | |||||
| public String toString() { | |||||
| return "while (" + condition + ") { " + program + " }"; | |||||
| } | |||||
| /*!- generated equals implementation */ | |||||
| @Override | @Override | ||||
| public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
| if (this == o) return true; | if (this == o) return true; | ||||
| @@ -22,16 +36,4 @@ public class Loop extends Program { | |||||
| return program.equals(loop.program); | return program.equals(loop.program); | ||||
| } | } | ||||
| @Override | |||||
| public String toString() { | |||||
| return "while (" + condition + ") { " + program + " }"; | |||||
| } | |||||
| @Override | |||||
| public int hashCode() { | |||||
| int result = condition.hashCode(); | |||||
| result = 31 * result + program.hashCode(); | |||||
| return result; | |||||
| } | |||||
| } | } | ||||
| @@ -1,4 +1,9 @@ | |||||
| /*!! Program*/ | |||||
| /*! # Program */ | |||||
| /*!- Header*/ | |||||
| package program; | package program; | ||||
| abstract public class Program { | |||||
| } | |||||
| /*! `Program` is the abstract common class for programs that can be exeuted using the `Interpreter`. */ | |||||
| abstract public class Program { } | |||||