| @@ -6,11 +6,14 @@ | |||
| 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)) | |||
| repräsentiert den Ausdruck | |||
| represents the code | |||
| x + 2 | |||
| */ | |||
| public class Addition extends Expression { | |||
| @@ -22,12 +25,13 @@ public class Addition extends Expression { | |||
| this.rightHandSide = rightHandSide; | |||
| } | |||
| /*!- Hilfsmethoden */ | |||
| /*!- String serialization */ | |||
| @Override | |||
| public String toString() { | |||
| return "(" + leftHandSide + " + " + rightHandSide + ")"; | |||
| } | |||
| /*!- Generated equals implementation */ | |||
| @Override | |||
| public boolean equals(Object o) { | |||
| if (this == o) return true; | |||
| @@ -39,11 +43,4 @@ public class Addition extends Expression { | |||
| 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; | |||
| 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 | |||
| public String toString() { | |||
| return name; | |||
| } | |||
| /*!- generated equals implementation */ | |||
| @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; | |||
| /*! | |||
| 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 final int value; | |||
| @@ -7,6 +16,13 @@ public class Int extends Expression { | |||
| this.value = value; | |||
| } | |||
| /*!- String serialization */ | |||
| @Override | |||
| public String toString() { | |||
| return Integer.toString(value); | |||
| } | |||
| /*!- generated equals implementation */ | |||
| @Override | |||
| public boolean equals(Object o) { | |||
| if (this == o) return true; | |||
| @@ -15,16 +31,5 @@ public class Int extends Expression { | |||
| Int integer = (Int) o; | |||
| 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; | |||
| /*! | |||
| 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 final Expression leftHandSide; | |||
| 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 | |||
| public boolean equals(Object o) { | |||
| if (this == o) return true; | |||
| @@ -15,21 +43,4 @@ public class Subtraction extends Expression { | |||
| 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 | |||
| 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 ";" Prog | | |||
| @@ -12,10 +17,10 @@ Dieser [rekursiv absteigende Parser](https://de.wikipedia.org/wiki/Rekursiver_Ab | |||
| Atom | |||
| 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 */ | |||
| @@ -29,26 +34,27 @@ import java.util.ArrayList; | |||
| 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"); | |||
| Program program = parser.parse(); | |||
| */ | |||
| 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; | |||
| String input; | |||
| final String input; | |||
| public Parser(String input) { | |||
| this.input = input; | |||
| } | |||
| public Program parse() { | |||
| position = 0; | |||
| Program program = program(); | |||
| @@ -1,38 +1,49 @@ | |||
| /*!! Program*/ | |||
| /*! # Program */ | |||
| /*!- Header */ | |||
| package program; | |||
| import expression.Expression; | |||
| 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 | |||
| public String toString() { | |||
| return identifier + " := " + expression; | |||
| } | |||
| /*!- generated equals method*/ | |||
| @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; | |||
| /*! A `Composition` combines two programs (`first` and `second`) with the intended semantics of sequential | |||
| composition. */ | |||
| public class Composition extends Program { | |||
| public final Program first; | |||
| 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 | |||
| public String toString() { | |||
| return first + " ; " + second; | |||
| } | |||
| /*!- generated equals implementation */ | |||
| @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; | |||
| 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 final Expression condition; | |||
| public final Program thenCase; | |||
| 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 | |||
| public boolean equals(Object o) { | |||
| if (this == o) return true; | |||
| @@ -20,22 +34,9 @@ public class Conditional extends Program { | |||
| } | |||
| /*!- String serialization*/ | |||
| @Override | |||
| public String toString() { | |||
| 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; | |||
| 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 final Expression condition; | |||
| public final Program program; | |||
| @@ -11,6 +18,13 @@ public class Loop extends Program { | |||
| this.program = program; | |||
| } | |||
| /*!- String serialization */ | |||
| @Override | |||
| public String toString() { | |||
| return "while (" + condition + ") { " + program + " }"; | |||
| } | |||
| /*!- generated equals implementation */ | |||
| @Override | |||
| public boolean equals(Object o) { | |||
| if (this == o) return true; | |||
| @@ -22,16 +36,4 @@ public class Loop extends 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; | |||
| abstract public class Program { | |||
| } | |||
| /*! `Program` is the abstract common class for programs that can be exeuted using the `Interpreter`. */ | |||
| abstract public class Program { } | |||